Repository: mprib/caliscope (language: python)

Issue:
Fix off-by-one issue in test_stream.py
The frame_index is currently being updated prior to the pause loop. While this can be fixed for the test easily, the GUI appears to be coded to manage the auto-stop of the playback and the enablement/disablement of the buttons with this error in place.

I need to find the place(s) in the GUI code where this is happening and make sure that things will be triggered correctly when the frame_index is updating as it should.


Discussion / hints:

Fix patch:
diff --git a/caliscope/__init__.py b/caliscope/__init__.py
index b110c2b6..6d1ee177 100644
--- a/caliscope/__init__.py
+++ b/caliscope/__init__.py
@@ -1,8 +1,10 @@
 """Top-level package for basic_template_repo."""
+
 import os
+import platform
 from pathlib import Path
+
 import rtoml
-import platform
 
 __package_name__ = "caliscope"
 __version__ = "v0.2.4"
@@ -10,26 +12,23 @@
 __author__ = """Mac Prible"""
 __email__ = "prible@gmail.com"
 __repo_owner_github_user_name__ = "mprib"
-__repo_url__ = (
-    f"https://github.com/{__repo_owner_github_user_name__}/{__package_name__}/"
-)
+__repo_url__ = f"https://github.com/{__repo_owner_github_user_name__}/{__package_name__}/"
 __repo_issues_url__ = f"{__repo_url__}issues"
 
 
-
 # Determine platform-specific application data directory
 if platform.system() == "Windows":
     print("Windows platform identified")
-    app_data_dir = os.getenv('LOCALAPPDATA')
+    app_data_dir = os.getenv("LOCALAPPDATA")
 else:  # macOS, Linux, and other UNIX variants
     print(f"Non-windows platform identified: {platform.system()}")
-    app_data_dir = os.path.join(os.path.expanduser("~"), '.local', 'share')
+    app_data_dir = os.path.join(os.path.expanduser("~"), ".local", "share")
 
 __app_dir__ = Path(app_data_dir, __package_name__)
 __app_dir__.mkdir(exist_ok=True, parents=True)
 
 # Create a toml file for user settings in app data directory and default the project folder to USER
-__settings_path__ = Path(__app_dir__, 'settings.toml')
+__settings_path__ = Path(__app_dir__, "settings.toml")
 
 # Get user home directory in a cross-platform way
 __user_dir__ = Path(os.path.expanduser("~"))
@@ -38,11 +37,13 @@
     USER_SETTINGS = rtoml.load(__settings_path__)
 else:
     # default to storing projects in user/__package_name__
-    USER_SETTINGS = {"recent_projects":[],
-                     "last_project_parent":str(__user_dir__) # default initially to home...this will be where the 'New' folder dialog starts
-                     } 
+    USER_SETTINGS = {
+        "recent_projects": [],
+        "last_project_parent": str(
+            __user_dir__
+        ),  # default initially to home...this will be where the 'New' folder dialog starts
+    }
 
-    
     with open(__settings_path__, "a") as f:
         rtoml.dump(USER_SETTINGS, f)
 
@@ -56,21 +57,20 @@
 
 print(f"This is printing from: {__file__}")
 print(f"Source code for this package is available at: {__repo_url__}")
-print(
-    f"Log file associated with {__package_name__} is stored in {__log_dir__}"
-)
+print(f"Log file associated with {__package_name__} is stored in {__log_dir__}")
 
 
-if __name__=="__main__":
+if __name__ == "__main__":
     import os
-    path = r'C:\Users\Mac Prible\AppData\Local\caliscope'
-    test_file = os.path.join(path, 'test.txt')
-    with open(test_file, 'w') as f:
-        f.write('Test')
+
+    path = r"C:\Users\Mac Prible\AppData\Local\caliscope"
+    test_file = os.path.join(path, "test.txt")
+    with open(test_file, "w") as f:
+        f.write("Test")
     print(f"Test file created at: {test_file}")
-    
-    
+
     import os
-    parent = r'C:\Users\Mac Prible\AppData\Local'
+
+    parent = r"C:\Users\Mac Prible\AppData\Local"
     print(os.path.exists(parent))
-    print(os.listdir(parent))
\ No newline at end of file
+    print(os.listdir(parent))
diff --git a/caliscope/__main__.py b/caliscope/__main__.py
index 49e04e14..64e2bde0 100644
--- a/caliscope/__main__.py
+++ b/caliscope/__main__.py
@@ -1,7 +1,7 @@
 import sys
 
-from caliscope.gui.main_widget import launch_main
 import caliscope.logger
+from caliscope.gui.main_widget import launch_main
 
 logger = caliscope.logger.get(__name__)
 
diff --git a/caliscope/calibration/capture_volume/capture_volume.py b/caliscope/calibration/capture_volume/capture_volume.py
index fb4eff1e..8f7c1f75 100644
--- a/caliscope/calibration/capture_volume/capture_volume.py
+++ b/caliscope/calibration/capture_volume/capture_volume.py
@@ -1,21 +1,20 @@
-#%%
+# %%
 
-import caliscope.logger
-
-
-from pathlib import Path
 import pickle
 from dataclasses import dataclass
-import numpy as np
+from pathlib import Path
+
 import cv2
+import numpy as np
 from scipy.optimize import least_squares
 
+import caliscope.logger
 from caliscope.calibration.capture_volume.point_estimates import PointEstimates
-from caliscope.calibration.charuco import Charuco
-from caliscope.cameras.camera_array import CameraArray
 from caliscope.calibration.capture_volume.set_origin_functions import (
     get_board_origin_transform,
 )
+from caliscope.calibration.charuco import Charuco
+from caliscope.cameras.camera_array import CameraArray
 
 logger = caliscope.logger.get(__name__)
 
@@ -31,15 +30,12 @@ class CaptureVolume:
 
     def __post__init__():
         logger.info("Creating capture volume from estimated camera array and stereotriangulated points...")
-        
+
     def _save(self, directory: Path, descriptor: str = None):
         if descriptor is None:
             pkl_name = "capture_volume_stage_" + str(self.stage) + ".pkl"
         else:
-
-            pkl_name = (
-                "capture_volume_stage_" + str(self.stage) + "_" + descriptor + ".pkl"
-            )
+            pkl_name = "capture_volume_stage_" + str(self.stage) + "_" + descriptor + ".pkl"
         logger.info(f"Saving stage {str(self.stage)} capture volume to {directory}")
         with open(Path(directory, pkl_name), "wb") as file:
             pickle.dump(self, file)
@@ -56,31 +52,26 @@ def get_vectorized_params(self):
 
     @property
     def rmse(self):
-
         if hasattr(self, "least_sq_result"):
-            rmse = rms_reproj_error(
-                self.least_sq_result.fun, self.point_estimates.camera_indices
-            )
+            rmse = rms_reproj_error(self.least_sq_result.fun, self.point_estimates.camera_indices)
         else:
             param_estimates = self.get_vectorized_params()
             xy_reproj_error = xy_reprojection_error(param_estimates, self)
-            rmse = rms_reproj_error(
-                xy_reproj_error, self.point_estimates.camera_indices
-            )
+            rmse = rms_reproj_error(xy_reproj_error, self.point_estimates.camera_indices)
 
         return rmse
 
     def get_rmse_summary(self):
         rmse_string = f"RMSE of Reprojection Overall: {round(self.rmse['overall'],2)}\n"
-        rmse_string+= "    by camera:\n"
+        rmse_string += "    by camera:\n"
         for key, value in self.rmse.items():
             if key == "overall":
                 pass
             else:
-                rmse_string+=f"    {key: >9}: {round(float(value),2)}\n"
+                rmse_string += f"    {key: >9}: {round(float(value),2)}\n"
 
         return rmse_string
-        
+
     def get_xy_reprojection_error(self):
         vectorized_params = self.get_vectorized_params()
         error = xy_reprojection_error(vectorized_params, self)
@@ -93,7 +84,7 @@ def optimize(self):
         initial_param_estimate = self.get_vectorized_params()
 
         # get a snapshot of where things are at the start
-        initial_xy_error = xy_reprojection_error(initial_param_estimate, self)
+        # initial_xy_error = xy_reprojection_error(initial_param_estimate, self)
 
         # logger.info(
         #     f"Prior to bundle adjustment (stage {str(self.stage)}), RMSE is: {self.rmse}"
@@ -116,9 +107,7 @@ def optimize(self):
         self.point_estimates.update_obj_xyz(self.least_sq_result.x)
         self.stage += 1
 
-        logger.info(
-            f"Following bundle adjustment (stage {str(self.stage)}), RMSE is: {self.rmse['overall']}"
-        )
+        logger.info(f"Following bundle adjustment (stage {str(self.stage)}), RMSE is: {self.rmse['overall']}")
 
     def get_xyz_points(self):
         """Get 3d positions arrived at by bundle adjustment"""
@@ -129,7 +118,6 @@ def get_xyz_points(self):
         return xyz
 
     def shift_origin(self, origin_shift_transform: np.ndarray):
-
         # update 3d point estimates
         xyz = self.point_estimates.obj
         scale = np.expand_dims(np.ones(xyz.shape[0]), 1)
@@ -140,9 +128,7 @@ def shift_origin(self, origin_shift_transform: np.ndarray):
 
         # update camera array
         for port, camera_data in self.camera_array.cameras.items():
-            camera_data.transformation = np.matmul(
-                camera_data.transformation, origin_shift_transform
-            )
+            camera_data.transformation = np.matmul(camera_data.transformation, origin_shift_transform)
 
     def set_origin_to_board(self, sync_index, charuco: Charuco):
         """
@@ -153,15 +139,14 @@ def set_origin_to_board(self, sync_index, charuco: Charuco):
 
         logger.info(f"Capture volume origin set to board position at sync index {sync_index}")
 
-        origin_transform = get_board_origin_transform(
-            self.camera_array, self.point_estimates, sync_index, charuco
-        )
+        origin_transform = get_board_origin_transform(self.camera_array, self.point_estimates, sync_index, charuco)
         self.shift_origin(origin_transform)
 
 
 def xy_reprojection_error(current_param_estimates, capture_volume: CaptureVolume):
     """
-    current_param_estimates: the current iteration of the vector that was originally initialized for the x0 input of least squares
+    current_param_estimates:
+        the current iteration of the vector that was originally initialized for the x0 input of least squares
 
     This function exists outside of the CaptureVolume class because the first argument must be the vector of parameters
     that is being adjusted by the least_squares optimization.
@@ -169,14 +154,14 @@ def xy_reprojection_error(current_param_estimates, capture_volume: CaptureVolume
     """
     # Create one combined array primarily to make sure all calculations line up
     ## unpack the working estimates of the camera parameters (could be extr. or intr.)
-    camera_params = current_param_estimates[
-        : capture_volume.point_estimates.n_cameras * CAMERA_PARAM_COUNT
-    ].reshape((capture_volume.point_estimates.n_cameras, CAMERA_PARAM_COUNT))
+    camera_params = current_param_estimates[: capture_volume.point_estimates.n_cameras * CAMERA_PARAM_COUNT].reshape(
+        (capture_volume.point_estimates.n_cameras, CAMERA_PARAM_COUNT)
+    )
 
     ## similarly unpack the 3d point location estimates
-    points_3d = current_param_estimates[
-        capture_volume.point_estimates.n_cameras * CAMERA_PARAM_COUNT :
-    ].reshape((capture_volume.point_estimates.n_obj_points, 3))
+    points_3d = current_param_estimates[capture_volume.point_estimates.n_cameras * CAMERA_PARAM_COUNT :].reshape(
+        (capture_volume.point_estimates.n_obj_points, 3)
+    )
 
     ## create zero columns as placeholders for the reprojected 2d points
     rows = capture_volume.point_estimates.camera_indices.shape[0]
@@ -195,7 +180,7 @@ def xy_reprojection_error(current_param_estimates, capture_volume: CaptureVolume
     # iterate across cameras...while this injects a loop in the residual function
     # it should scale linearly with the number of cameras...a tradeoff for stable
     # and explicit calculations...
-    
+
     for port, cam in capture_volume.camera_array.cameras.items():
         cam_points = np.where(capture_volume.point_estimates.camera_indices == port)
         object_points = points_3d_and_2d[cam_points][:, 1:4]
@@ -209,9 +194,7 @@ def xy_reprojection_error(current_param_estimates, capture_volume: CaptureVolume
         distortions = cam.distortions
 
         # get the projection of the 2d points on the image plane; ignore the jacobian
-        cam_proj_points, _jac = cv2.projectPoints(
-            object_points.astype(np.float64), rvec, tvec, cam_matrix, distortions
-        )
+        cam_proj_points, _jac = cv2.projectPoints(object_points.astype(np.float64), rvec, tvec, cam_matrix, distortions)
 
         points_3d_and_2d[cam_points, 6:8] = cam_proj_points[:, 0, :]
 
@@ -245,14 +228,15 @@ def rms_reproj_error(xy_reproj_error, camera_indices):
     # logger.info(f"RMSE of reprojection is {rmse}")
     return rmse
 
+
 # def load_capture_volume(session_path:Path):
 #     config = get_config(session_directory)
 
 #     camera_array = get_camera_array(config)
 #     point_estimates = load_point_estimates(config)
-    
-#     capture_volume = CaptureVolume(camera_array, point_estimates)    
+
+#     capture_volume = CaptureVolume(camera_array, point_estimates)
 #     capture_volume.stage = config["capture_volume"]["stage"]
 #     # capture_volume.origin_sync_index = config["capture_volume"]["origin_sync_index"]
 
-#     return capture_volume
\ No newline at end of file
+#     return capture_volume
diff --git a/caliscope/calibration/capture_volume/helper_functions/get_point_estimates.py b/caliscope/calibration/capture_volume/helper_functions/get_point_estimates.py
index 79f84371..39ed1dbd 100644
--- a/caliscope/calibration/capture_volume/helper_functions/get_point_estimates.py
+++ b/caliscope/calibration/capture_volume/helper_functions/get_point_estimates.py
@@ -1,19 +1,20 @@
-import caliscope.logger
-logger = caliscope.logger.get(__name__)
+from pathlib import Path
 
-import pandas as pd
 import numpy as np
-from caliscope.cameras.camera_array import CameraArray
+import pandas as pd
 
+import caliscope.logger
+from caliscope.calibration.capture_volume.helper_functions.get_stereotriangulated_table import (
+    get_stereotriangulated_table,
+)
 from caliscope.calibration.capture_volume.point_estimates import PointEstimates
-from caliscope.calibration.capture_volume.helper_functions.get_stereotriangulated_table import get_stereotriangulated_table
-from pathlib import Path
+from caliscope.cameras.camera_array import CameraArray
+
+logger = caliscope.logger.get(__name__)
 
-def get_points_2d_df(stereotriangulated_table:pd.DataFrame):
 
-    points_2d_port_A = stereotriangulated_table[
-        ["port_A", "sync_index", "point_id", "x_A", "y_A"]
-    ].rename(
+def get_points_2d_df(stereotriangulated_table: pd.DataFrame):
+    points_2d_port_A = stereotriangulated_table[["port_A", "sync_index", "point_id", "x_A", "y_A"]].rename(
         columns={
             "port_A": "camera",
             "sync_index": "sync_index",
@@ -23,9 +24,7 @@ def get_points_2d_df(stereotriangulated_table:pd.DataFrame):
         }
     )
 
-    points_2d_port_B = stereotriangulated_table[
-        ["port_B", "sync_index", "point_id", "x_B", "y_B"]
-    ].rename(
+    points_2d_port_B = stereotriangulated_table[["port_B", "sync_index", "point_id", "x_B", "y_B"]].rename(
         columns={
             "port_B": "camera",
             "sync_index": "sync_index",
@@ -46,15 +45,12 @@ def get_points_2d_df(stereotriangulated_table:pd.DataFrame):
 
 # get 3d points with indices to merge back into points_2d
 def get_points_3d_df(stereotriangulated_table):
-
     points_3d_df = (
         stereotriangulated_table[["sync_index", "point_id", "pair", "x_pos", "y_pos", "z_pos"]]
         .sort_values(["sync_index", "point_id"])
         .groupby(["sync_index", "point_id"])
         .agg({"x_pos": "mean", "y_pos": "mean", "z_pos": "mean", "pair": "size"})
-        .rename(
-            columns={"pair": "count", "x_pos": "x_3d", "y_pos": "y_3d", "z_pos": "z_3d"}
-        )
+        .rename(columns={"pair": "count", "x_pos": "x_3d", "y_pos": "y_3d", "z_pos": "z_3d"})
         .reset_index()
         .reset_index()
         .rename(columns={"index": "index_3d", "point_id": "corner_id"})
@@ -78,17 +74,15 @@ def get_merged_2d_3d(stereotriangulated_table):
     return merged_point_data
 
 
-def get_point_estimates(camera_array:CameraArray, point_data_path: Path) -> PointEstimates:
+def get_point_estimates(camera_array: CameraArray, point_data_path: Path) -> PointEstimates:
     """
-    formats the triangulated_points.csv file into a PointEstimateData that has the 
+    formats the triangulated_points.csv file into a PointEstimateData that has the
     data structured in a way that is amenable to bundle adjustment
     """
 
-    
     logger.info("Creating point history object based on camera_array and stereotriangulated_table")
     stereotriangulated_points = get_stereotriangulated_table(camera_array, point_data_path)
-    
-    
+
     points_3d_df = get_points_3d_df(stereotriangulated_points)
     merged_point_data = get_merged_2d_3d(stereotriangulated_points)
 
diff --git a/caliscope/calibration/capture_volume/helper_functions/get_stereotriangulated_table.py b/caliscope/calibration/capture_volume/helper_functions/get_stereotriangulated_table.py
index 23aa9586..2d7a82bd 100644
--- a/caliscope/calibration/capture_volume/helper_functions/get_stereotriangulated_table.py
+++ b/caliscope/calibration/capture_volume/helper_functions/get_stereotriangulated_table.py
@@ -2,37 +2,32 @@
 # all of the data is ultimately embedded in the initial camera array configuration
 # and the calibration point data. These functions transform those two
 # things into a PointHistory object that can be used to optimize the CaptureVolume
-import caliscope.logger
-
+from pathlib import Path
 
-import pandas as pd
 import numpy as np
-from pathlib import Path
+import pandas as pd
 
-from caliscope.packets import PointPacket, FramePacket, SyncPacket
+import caliscope.logger
 from caliscope.cameras.camera_array import CameraArray
+from caliscope.packets import FramePacket, PointPacket, SyncPacket
 from caliscope.triangulate.array_stereo_triangulator import ArrayStereoTriangulator
-
 from caliscope.triangulate.stereo_points_builder import (
     StereoPointsBuilder,
     StereoPointsPacket,
     SynchedStereoPointsPacket,
 )
+
 logger = caliscope.logger.get(__name__)
 
 
-def get_stereotriangulated_table(
-    camera_array: CameraArray, point_data_path: Path
-) -> pd.DataFrame:
-    logger.info(
-        f"Beginning to create stereotriangulated points from data stored at {point_data_path}"
-    )
+def get_stereotriangulated_table(camera_array: CameraArray, point_data_path: Path) -> pd.DataFrame:
+    logger.info(f"Beginning to create stereotriangulated points from data stored at {point_data_path}")
     point_data = pd.read_csv(point_data_path)
 
     xy_sync_indices = point_data["sync_index"].to_numpy()
     sync_indices = np.unique(xy_sync_indices)
 
-    xy_camera_indices = point_data["port"].to_numpy()
+    # xy_camera_indices = point_data["port"].to_numpy()
     # ports = np.unique(xy_camera_indices)
     ports = [key for key in camera_array.port_index.keys()]
 
@@ -45,9 +40,7 @@ def get_stereotriangulated_table(
     logger.info("Begin reconstructing SyncPackets and SynchedStereoPairs... ")
     for sync_index in sync_indices:
         if sync_index % 25 == 0:
-            logger.info(
-                f"Processing stereotriangulation estimates...currently at sync index {sync_index}"
-            )
+            logger.info(f"Processing stereotriangulation estimates...currently at sync index {sync_index}")
         # pull in the data that shares the same sync index
         port_points = point_data.query(f"sync_index == {sync_index}")
 
@@ -88,16 +81,12 @@ def get_stereotriangulated_table(
         sync_packet = SyncPacket(sync_index, frame_packets)
 
         # get the paired point packets for all port pairs at this sync index
-        synched_stereo_points: SynchedStereoPointsPacket = (
-            paired_point_builder.get_synched_paired_points(sync_packet)
-        )
+        synched_stereo_points: SynchedStereoPointsPacket = paired_point_builder.get_synched_paired_points(sync_packet)
         # print(synched_paired_points)
         array_triangulator.triangulate_synched_points(synched_stereo_points)
 
         for pair in synched_stereo_points.pairs:
-            triangulated_pair: StereoPointsPacket = (
-                synched_stereo_points.stereo_points_packets[pair]
-            )
+            triangulated_pair: StereoPointsPacket = synched_stereo_points.stereo_points_packets[pair]
             if triangulated_pair is not None:
                 if stereotriangulated_table is None:
                     stereotriangulated_table = triangulated_pair.to_table()
@@ -106,13 +95,9 @@ def get_stereotriangulated_table(
                     for key, value in new_table.items():
                         stereotriangulated_table[key].extend(value)
 
-    logger.info(
-        f"Saving stereotriangulated_points.csv to {point_data_path.parent} for inspection"
-    )
+    logger.info(f"Saving stereotriangulated_points.csv to {point_data_path.parent} for inspection")
     stereotriangulated_table = pd.DataFrame(stereotriangulated_table)
-    stereotriangulated_table.to_csv(
-        Path(point_data_path.parent, "stereotriangulated_points.csv")
-    )
+    stereotriangulated_table.to_csv(Path(point_data_path.parent, "stereotriangulated_points.csv"))
 
     logger.info("Returning dataframe of stereotriangulated points to caller")
 
diff --git a/caliscope/calibration/capture_volume/point_estimates.py b/caliscope/calibration/capture_volume/point_estimates.py
index 27120392..7a834b3f 100644
--- a/caliscope/calibration/capture_volume/point_estimates.py
+++ b/caliscope/calibration/capture_volume/point_estimates.py
@@ -1,21 +1,13 @@
-# import saved point data and initial array configuration data
-# currently this is for the convenience of not having to rerun everything
-# though this workflow may be useful into the future. Save out milestone calculations
-# along the way that allow for blocks of dataprocessing
-#%%
-import caliscope.logger
-logger = caliscope.logger.get(__name__)
-
-from pathlib import Path
+from dataclasses import dataclass
 
+import numpy as np
 from scipy.sparse import lil_matrix
 
-import pandas as pd
-import numpy as np
-from dataclasses import dataclass
-from caliscope.calibration.capture_volume.helper_functions.get_stereotriangulated_table import get_stereotriangulated_table
+import caliscope.logger
+
+logger = caliscope.logger.get(__name__)
 
-CAMERA_PARAM_COUNT = 6  # this will evolve when moving from extrinsic to intrinsic
+CAMERA_PARAM_COUNT = 6
 
 
 @dataclass
@@ -24,24 +16,23 @@ class PointEstimates:
     Initialized from triangulated_points.csv to provide the formatting of data required for bundle adjustment
     "full" is used here because there is currently a method to filter the data based on reprojection error
     Not sure if it will be used going forward, but it remains here if so.
-    """ 
+    """
 
     sync_indices: np.ndarray  # the sync_index from when the image was taken
     camera_indices: np.ndarray  # camera id associated with the img point
-    point_id: np.ndarray # point id (i.e. charuco corner currently)
+    point_id: np.ndarray  # point id (i.e. charuco corner currently)
     img: np.ndarray  # x,y coords of point
-    obj_indices: np.ndarray # mapping of x,y img points to their respective list of estimated x,y,z obj points
+    obj_indices: np.ndarray  # mapping of x,y img points to their respective list of estimated x,y,z obj points
     obj: np.ndarray  # x,y,z estimates of object points
     # obj_corner_id: np.ndarray # the charuco corner ID of the xyz object point; is this necessary?
 
-
     def __post_init__(self):
         self.sync_indices = self.sync_indices.astype(np.int32)
         self.camera_indices = self.camera_indices.astype(np.int16)
         self.point_id = self.point_id.astype(np.uint16)
         self.img = self.img.astype(np.float64)
         self.obj_indices = self.obj_indices.astype(np.int32)
-        self.obj = self.obj.astype(np.float64)    
+        self.obj = self.obj.astype(np.float64)
 
     @property
     def n_cameras(self):
@@ -56,8 +47,11 @@ def n_img_points(self):
         return self.img.shape[0]
 
     def get_sparsity_pattern(self):
-        """provide the sparsity structure for the Jacobian (elements that are not zero)
-        n_points: number of unique 3d points; these will each have at least one but potentially more associated 2d points
+        """
+        provide the sparsity structure for the Jacobian (elements that are not zero)
+        n_points: number of unique 3d points
+            these will each have at least one but potentially more associated 2d points
+
         point_indices: a vector that maps the 2d points to their associated 3d point
         """
 
@@ -84,16 +78,14 @@ def update_obj_xyz(self, least_sq_result_x):
         Provided with the least_squares estimate of the best fit of model parameters (including camera 6DoF)
         parse out the x,y,z object positions and update self.obj
         """
-        
+
         xyz = least_sq_result_x[self.n_cameras * CAMERA_PARAM_COUNT :]
         xyz = xyz.reshape(-1, 3)
 
         self.obj = xyz
-        
-        
-        
- 
-def load_point_estimates(config:dict)->PointEstimates:
+
+
+def load_point_estimates(config: dict) -> PointEstimates:
     point_estimates_dict = config["point_estimates"]
 
     for key, value in point_estimates_dict.items():
@@ -101,4 +93,3 @@ def load_point_estimates(config:dict)->PointEstimates:
 
     point_estimates = PointEstimates(**point_estimates_dict)
     return point_estimates
-
diff --git a/caliscope/calibration/capture_volume/quality_controller.py b/caliscope/calibration/capture_volume/quality_controller.py
index cbb9f7e5..67dcf534 100644
--- a/caliscope/calibration/capture_volume/quality_controller.py
+++ b/caliscope/calibration/capture_volume/quality_controller.py
@@ -1,29 +1,24 @@
-#%%
-import caliscope.logger
-
-logger = caliscope.logger.get(__name__)
-
-from pathlib import Path
+# %%
 import pickle
-import sys
-from scipy import stats
+from pathlib import Path
+
 import numpy as np
 import pandas as pd
 import rtoml
-from caliscope.calibration.charuco import Charuco
-from caliscope.calibration.capture_volume.capture_volume import (
-    CaptureVolume,
-    xy_reprojection_error,
-)
+from scipy import stats
 
+import caliscope.logger
+from caliscope.calibration.capture_volume.capture_volume import CaptureVolume, xy_reprojection_error
 from caliscope.calibration.capture_volume.point_estimates import PointEstimates
+from caliscope.calibration.charuco import Charuco
+
+logger = caliscope.logger.get(__name__)
+
 
 class QualityController:
-    def __init__(self, capture_volume:CaptureVolume, charuco:Charuco = None):
+    def __init__(self, capture_volume: CaptureVolume, charuco: Charuco = None):
         self.charuco = charuco
         self.capture_volume = capture_volume
-        # self.all_data_2d = None
-        # self.all_distance_error = None
 
     # not sure if the below is getting used anymore as distance_error appears to hold everything
     # maybe I was envisioning the distance error across all stages? I think so. I also don't know
@@ -34,24 +29,23 @@ def __init__(self, capture_volume:CaptureVolume, charuco:Charuco = None):
     #         self.all_data_2d = self.data_2d
     #     else:
     #         self.all_data_2d = pd.concat([self.all_data_2d, self.data_2d])
-  
+
     #     # only create this data if the charuco was provided
-    #     if self.charuco is not None: 
+    #     if self.charuco is not None:
     #         if self.all_distance_error is None:
     #             self.all_distance_error = self.distance_error
     #         else:
     #             self.all_distance_error = pd.concat([self.all_distance_error, self.distance_error])
-    
+
     @property
     def data_2d(self) -> pd.DataFrame:
-        """
-        Unpack the Array Diagnostic data into a pandas dataframe format that can be
+        """Unpack the Array Diagnostic data into a pandas dataframe format that can be
         plotted and summarized. This is all 2d data observations with their
         corresponding 3d point estimates (meaning the 3d point data is duplicated)
         """
-
         capture_volume_xy_error = xy_reprojection_error(
-            self.capture_volume.get_vectorized_params(), self.capture_volume
+            self.capture_volume.get_vectorized_params(),
+            self.capture_volume,
         ).reshape(-1, 2)
         # build out error as singular distanc
 
@@ -61,10 +55,10 @@ def data_2d(self) -> pd.DataFrame:
         row_count = euclidean_distance_error.shape[0]
 
         array_data_dict = {
-            "stage": [self.capture_volume.stage]*row_count, 
+            "stage": [self.capture_volume.stage] * row_count,
             "camera": self.capture_volume.point_estimates.camera_indices.tolist(),
             "sync_index": self.capture_volume.point_estimates.sync_indices.astype(
-                int
+                int,
             ).tolist(),
             "charuco_id": self.capture_volume.point_estimates.point_id.tolist(),
             "img_x": self.capture_volume.point_estimates.img[:, 0].tolist(),
@@ -75,37 +69,37 @@ def data_2d(self) -> pd.DataFrame:
             "reproj_error_sq": (euclidean_distance_error**2).tolist(),
             "obj_id": self.capture_volume.point_estimates.obj_indices.tolist(),
             "obj_x": xyz[self.capture_volume.point_estimates.obj_indices][
-                :, 0
+                :,
+                0,
             ].tolist(),
             "obj_y": xyz[self.capture_volume.point_estimates.obj_indices][
-                :, 1
+                :,
+                1,
             ].tolist(),
             "obj_z": xyz[self.capture_volume.point_estimates.obj_indices][
-                :, 2
+                :,
+                2,
             ].tolist(),
         }
 
         summarized_data = pd.DataFrame(array_data_dict).astype(
-            {"sync_index": "int32", "charuco_id": "int32", "obj_id": "int32"}
+            {"sync_index": "int32", "charuco_id": "int32", "obj_id": "int32"},
         )
 
         summarized_data["reproj_error_percentile"] = stats.percentileofscore(
-            summarized_data["reproj_error"], summarized_data["reproj_error"]
+            summarized_data["reproj_error"],
+            summarized_data["reproj_error"],
         )
 
         return summarized_data
 
     @property
     def corners_world_xyz(self) -> pd.DataFrame:
-        """
-        convert the table of 2d data observations to a smaller table of only the individual 3d point
+        """Convert the table of 2d data observations to a smaller table of only the individual 3d point
         estimates. These will have a number of duplicates so drop them.
         """
-
         corners_3d = (
-            self.data_2d[
-                ["sync_index", "charuco_id", "obj_id", "obj_x", "obj_y", "obj_z"]
-            ]
+            self.data_2d[["sync_index", "charuco_id", "obj_id", "obj_x", "obj_y", "obj_z"]]
             .astype({"sync_index": "int32", "charuco_id": "int32", "obj_id": "int32"})
             .drop_duplicates()
             .sort_values(by=["obj_id"])
@@ -116,10 +110,10 @@ def corners_world_xyz(self) -> pd.DataFrame:
 
     @property
     def paired_obj_indices(self) -> np.ndarray:
-        """given a dataframe that contains all observed charuco corners across sync_indices,
+        """Given a dataframe that contains all observed charuco corners across sync_indices,
         return a Nx2 matrix of paired object indices that will represent all possible
-        joined lines between charuco corners for each sync_index"""
-
+        joined lines between charuco corners for each sync_index
+        """
         # get columns out from data frame for numpy calculations
         sync_indices = self.corners_world_xyz["sync_index"].to_numpy(dtype=np.int32)
         unique_sync_indices = np.unique(sync_indices)
@@ -128,9 +122,7 @@ def paired_obj_indices(self) -> np.ndarray:
         # for a given sync index (i.e. one board snapshot) get all pairs of object ids
         paired_obj_indices = None
         for x in unique_sync_indices:
-            sync_obj = obj_id[
-                sync_indices == x
-            ]  # 3d objects (corners) at a specific sync_index
+            sync_obj = obj_id[sync_indices == x]  # 3d objects (corners) at a specific sync_index
             all_pairs = cartesian_product(sync_obj, sync_obj)
             if paired_obj_indices is None:
                 paired_obj_indices = all_pairs
@@ -140,16 +132,20 @@ def paired_obj_indices(self) -> np.ndarray:
         # paired_corner_indices will contain duplicates (i.e. [0,1] and [1,0]) as well as self-pairs ([0,0], [1,1])
         # this need to get filtered out
         reformatted_paired_obj_indices = np.zeros(
-            paired_obj_indices.shape, dtype=np.int32
+            paired_obj_indices.shape,
+            dtype=np.int32,
         )
         reformatted_paired_obj_indices[:, 0] = np.min(
-            paired_obj_indices, axis=1
+            paired_obj_indices,
+            axis=1,
         )  # smaller on left
         reformatted_paired_obj_indices[:, 1] = np.max(
-            paired_obj_indices, axis=1
+            paired_obj_indices,
+            axis=1,
         )  # larger on right
         reformatted_paired_obj_indices = np.unique(
-            reformatted_paired_obj_indices, axis=0
+            reformatted_paired_obj_indices,
+            axis=0,
         )
         reformatted_paired_obj_indices = reformatted_paired_obj_indices[
             reformatted_paired_obj_indices[:, 0] != reformatted_paired_obj_indices[:, 1]
@@ -169,9 +165,7 @@ def distance_error(self) -> pd.DataFrame:
         logger.info("Beginning to calculate distance error")
 
         # temp numpy frame for working calculations
-        corners_world_xyz = self.corners_world_xyz[
-            ["obj_x", "obj_y", "obj_z"]
-        ].to_numpy()
+        corners_world_xyz = self.corners_world_xyz[["obj_x", "obj_y", "obj_z"]].to_numpy()
         corners_board_xyz = self.corners_board_xyz
 
         # get the xyz positions for all pairs of corners
@@ -182,10 +176,10 @@ def distance_error(self) -> pd.DataFrame:
 
         # get the distance between them
         distance_world_A_B = np.sqrt(
-            np.sum((corners_world_A - corners_world_B) ** 2, axis=1)
+            np.sum((corners_world_A - corners_world_B) ** 2, axis=1),
         )
         distance_board_A_B = np.sqrt(
-            np.sum((corners_board_A - corners_board_B) ** 2, axis=1)
+            np.sum((corners_board_A - corners_board_B) ** 2, axis=1),
         )
 
         distance_world_A_B = np.round(distance_world_A_B, 5)
@@ -193,54 +187,60 @@ def distance_error(self) -> pd.DataFrame:
 
         # calculate error (in mm)
         distance_error = distance_world_A_B - distance_board_A_B
-        
+
         # wrap everything up in a dataframe for ease of processing
         distance_error = pd.DataFrame(distance_error, columns=["Distance_Error"])
         distance_error["Distance_Error_mm"] = distance_error["Distance_Error"] * 1000
         distance_error["Distance_Error_mm_abs"] = abs(
-            distance_error["Distance_Error_mm"]
+            distance_error["Distance_Error_mm"],
         )
 
-        distance_error["corner_A"] = self.paired_obj_indices[:,0]
-        distance_error["corner_B"] = self.paired_obj_indices[:,1]
+        distance_error["corner_A"] = self.paired_obj_indices[:, 0]
+        distance_error["corner_B"] = self.paired_obj_indices[:, 1]
 
-        distance_error["world_distance"] = distance_world_A_B       
+        distance_error["world_distance"] = distance_world_A_B
         distance_error["board_distance"] = distance_board_A_B
-        distance_error["percent_match"] = distance_world_A_B/distance_board_A_B      
+        distance_error["percent_match"] = distance_world_A_B / distance_board_A_B
         distance_error["stage"] = self.capture_volume.stage
 
         logger.info("returning distance error")
-        
+
         return distance_error
 
     @property
     def distance_error_summary(self):
         logger.info("returning summary of distance error statistics")
 
-        summary = self.distance_error.groupby('board_distance').agg({
-            'Distance_Error_mm_abs': ['mean', 'std'],
-            'Distance_Error_mm': ['mean', 'std'],
-        }).reset_index()
+        summary = (
+            self.distance_error.groupby("board_distance")
+            .agg(
+                {
+                    "Distance_Error_mm_abs": ["mean", "std"],
+                    "Distance_Error_mm": ["mean", "std"],
+                }
+            )
+            .reset_index()
+        )
 
         # flatten the multi-level column index
-        summary.columns = ['_'.join(col).strip() for col in summary.columns.values]
+        summary.columns = ["_".join(col).strip() for col in summary.columns.values]
         # rename the "Distance_error_mm_abs" column to "Distance_Error_mm"
-        summary["board_distance_"]   = summary["board_distance_"]*1000
+        summary["board_distance_"] = summary["board_distance_"] * 1000
 
         summary = summary.round(2)
         summary = summary.astype(str)
-    
-        summary["|Distance Error|"] = summary["Distance_Error_mm_abs_mean"] +" (" + summary["Distance_Error_mm_abs_std"] + ")"
-        summary["Distance Error"] = summary["Distance_Error_mm_mean"] +" (" + summary["Distance_Error_mm_std"] + ")"
-    
-        summary = summary.rename(columns={"board_distance_":"Board Distance"})
+
+        summary["|Distance Error|"] = (
+            summary["Distance_Error_mm_abs_mean"] + " (" + summary["Distance_Error_mm_abs_std"] + ")"
+        )
+        summary["Distance Error"] = summary["Distance_Error_mm_mean"] + " (" + summary["Distance_Error_mm_std"] + ")"
+
+        summary = summary.rename(columns={"board_distance_": "Board Distance"})
         summary = summary[["Board Distance", "Distance Error", "|Distance Error|"]]
         return summary
 
-        
     def get_filtered_data_2d(self, percentile_cutoff: float):
-        """
-        Provided a cutoff percentile value, returns a filtered_data_2d dataframe
+        """Provided a cutoff percentile value, returns a filtered_data_2d dataframe
         that only represents observations that have a reprojection error below
         that threshold. Additionally, it removes any singular 2d observations
         (i.e. those that have only one snapshot image and therefore cannot
@@ -248,10 +248,9 @@ def get_filtered_data_2d(self, percentile_cutoff: float):
 
         percentile_cutoff: a fraction between 0 and 1
         """
-
         # filter data based on reprojection error
         filtered_data_2d = self.data_2d.query(
-            f"reproj_error_percentile <{str(percentile_cutoff*100)}"
+            f"reproj_error_percentile <{percentile_cutoff*100!s}",
         )
 
         # get the count of obj_ids to understand how many times
@@ -268,10 +267,10 @@ def get_filtered_data_2d(self, percentile_cutoff: float):
 
         # remove any points that now only have 1 2d image associated with them
         filtered_data_2d = filtered_data_2d.query("obj_id_count > 1").rename(
-            columns={"obj_id": "original_obj_id"}
+            columns={"obj_id": "original_obj_id"},
         )
         return filtered_data_2d
-    
+
     def filter_point_estimates(self, fraction_to_remove: float):
         percentile_cutoff = 1 - fraction_to_remove
         filtered_data_2d = self.get_filtered_data_2d(percentile_cutoff)
@@ -282,11 +281,11 @@ def filter_point_estimates(self, fraction_to_remove: float):
             .reset_index()
             .drop("index", axis=1)
             .reset_index()
-            .rename(columns={"index":"filtered_obj_id"})
+            .rename(columns={"index": "filtered_obj_id"})
         )
-    
+
         old_new_mapping = objects_3d.filter(["filtered_obj_id", "original_obj_id"])
-    
+
         filtered_data_2d = filtered_data_2d.merge(old_new_mapping, how="right", on=["original_obj_id"])
 
         # get revised point_estimates
@@ -303,20 +302,21 @@ def filter_point_estimates(self, fraction_to_remove: float):
             point_id=point_id,
             img=img,
             obj_indices=obj_indices,
-            obj=obj
+            obj=obj,
         )
-        
+
         self.capture_volume.point_estimates = filtered_point_estimates
-        
+
 
 def get_capture_volume(capture_volume_pkl_path: Path) -> CaptureVolume:
     logger.info(f"loading capture volume from {capture_volume_pkl_path}")
     with open(capture_volume_pkl_path, "rb") as file:
-        logger.info(f"beginning to load file....")
+        logger.info("beginning to load file....")
         capture_volume = pickle.load(file)
-        logger.info(f"file loaded...")
+        logger.info("file loaded...")
     return capture_volume
 
+
 def get_charuco(config_path) -> Charuco:
     config = rtoml.load(config_path)
 
@@ -335,9 +335,10 @@ def get_charuco(config_path) -> Charuco:
 
     return charuco
 
+
 def cartesian_product(*arrays):
     """
-    helper function for creating all possible pairs of points within a given sync_index
+    Helper function for creating all possible pairs of points within a given sync_index
     https://stackoverflow.com/questions/11144513/cartesian-product-of-x-and-y-array-points-into-single-array-of-2d-points
     """
     la = len(arrays)
@@ -349,14 +350,14 @@ def cartesian_product(*arrays):
 
 
 if __name__ == "__main__":
-# if True:
-    from caliscope.session.session import LiveSession
+    # if True:
     from caliscope import __root__
+    from caliscope.session.session import LiveSession
 
     session_directory = Path(__root__, "tests", "217")
-    # config_path = Path(session_directory, "config.toml")  
+    # config_path = Path(session_directory, "config.toml")
     # capture_volume_name = "capture_volume_stage_0.pkl"
-    
+
     # get the inputs for quality control (CaptureVolume and Charuco)
     # capture_volume = get_capture_volume(Path(session_directory,capture_volume_name))
     # charuco = get_charuco(config_path)
@@ -366,21 +367,9 @@ def cartesian_product(*arrays):
     session.load_estimated_capture_volume()
     quality_controller = QualityController(session.capture_volume)
 
-    # quality_controller.capture_volume.optimize()
-
-    # store stage 1 data (initial optimization)
-    # quality_controller.capture_volume.save(session_directory)
-    # quality_controller.store_data()    
-    
     logger.info(quality_controller.capture_volume.stage)
-    
-    for _ in range(0,5):
+
+    for _ in range(5):
         logger.info("Filtering out worst fitting point estimates")
-        quality_controller.filter_point_estimates(.95)
+        quality_controller.filter_point_estimates(0.95)
         quality_controller.capture_volume.optimize()
-        # print(quality_controller.capture_volume._rmse)
-    # quality_controller.store_data()    
-    # quality_controller.capture_volume.save(session_directory)
-
-    # quality_controller.all_data_2d.to_csv(Path(session_directory, "data_2d.csv"))
-# %%
diff --git a/caliscope/calibration/capture_volume/seaborn_summaries.py b/caliscope/calibration/capture_volume/seaborn_summaries.py
index 66c316d9..3981b878 100644
--- a/caliscope/calibration/capture_volume/seaborn_summaries.py
+++ b/caliscope/calibration/capture_volume/seaborn_summaries.py
@@ -1,54 +1,52 @@
-#%%
+# %%
 
 from pathlib import Path
+
+import numpy as np
 import pandas as pd
-from caliscope import __root__
 import seaborn as sns
-import numpy as np
+
+from caliscope import __root__
 
 session_directory = Path(__root__, "tests", "demo")
 
 
-data_2d = pd.read_csv(Path(session_directory,"data_2d.csv"))
-distance_error = pd.read_csv(Path(session_directory,"distance_error.csv"))
+data_2d = pd.read_csv(Path(session_directory, "data_2d.csv"))
+distance_error = pd.read_csv(Path(session_directory, "distance_error.csv"))
 
 
 # %%
 facet_reproj_error = sns.FacetGrid(data_2d, col="camera", col_wrap=2)
-facet_reproj_error.map_dataframe(sns.boxplot, x = "stage", y = "reproj_error", showfliers=False)
+facet_reproj_error.map_dataframe(sns.boxplot, x="stage", y="reproj_error", showfliers=False)
 # %%
-facet_distance_error = sns.FacetGrid(distance_error,row="board_distance")
-facet_distance_error.map_dataframe(sns.boxplot, x="stage", y = "Distance_Error_mm", showfliers=False)
+facet_distance_error = sns.FacetGrid(distance_error, row="board_distance")
+facet_distance_error.map_dataframe(sns.boxplot, x="stage", y="Distance_Error_mm", showfliers=False)
 # sns.boxplot(data = distance_error, x = "stage", y = "Distance_Error_mm_abs", showfliers=False)
-#%%
-facet_distance_error = sns.FacetGrid(distance_error,row="board_distance")
-facet_distance_error.map_dataframe(sns.boxplot, x="stage", y = "percent_match", showfliers=False)
+# %%
+facet_distance_error = sns.FacetGrid(distance_error, row="board_distance")
+facet_distance_error.map_dataframe(sns.boxplot, x="stage", y="percent_match", showfliers=False)
 
 # %%
 
-by_board_distance = (distance_error
-                     .filter(["Distance_Error_mm", "Distance_Error_mm_abs", "world_distance", "board_distance"])
-                     .groupby("board_distance")
-                     .mean()
-            )
+by_board_distance = (
+    distance_error.filter(["Distance_Error_mm", "Distance_Error_mm_abs", "world_distance", "board_distance"])
+    .groupby("board_distance")
+    .mean()
+)
 
 # %%
 
-rmse = (data_2d.filter(["reproj_error_sq"])
-                  .mean())
+rmse = data_2d.filter(["reproj_error_sq"]).mean()
 
-rmse_by_camera = (data_2d.filter(["camera", "reproj_error_sq"])
-                  .groupby("camera")
-                  .mean(["reproj_error_sq"])
-                  .rename(columns={"reproj_error_sq":"mean_sq_error"}))
-rmse_by_camera["rmse"]=np.sqrt(rmse_by_camera["mean_sq_error"])
+rmse_by_camera = (
+    data_2d.filter(["camera", "reproj_error_sq"])
+    .groupby("camera")
+    .mean(["reproj_error_sq"])
+    .rename(columns={"reproj_error_sq": "mean_sq_error"})
+)
+rmse_by_camera["rmse"] = np.sqrt(rmse_by_camera["mean_sq_error"])
 
-#%%
-
-sns.boxplot(data = distance_error, 
-            x="board_distance", 
-            y= "Distance_Error_mm_abs",
-            showfliers = False
+# %%
 
-            )
+sns.boxplot(data=distance_error, x="board_distance", y="Distance_Error_mm_abs", showfliers=False)
 # %%
diff --git a/caliscope/calibration/capture_volume/set_origin_functions.py b/caliscope/calibration/capture_volume/set_origin_functions.py
index cebe2d74..dc61bfbc 100644
--- a/caliscope/calibration/capture_volume/set_origin_functions.py
+++ b/caliscope/calibration/capture_volume/set_origin_functions.py
@@ -1,31 +1,31 @@
 # %%
-import caliscope.logger
-
-logger = caliscope.logger.get(__name__)
 
+import pickle
+import sys
 from pathlib import Path
+
+import cv2
 import numpy as np
-import sys
 import scipy
 from PySide6.QtWidgets import QApplication
+
+import caliscope.logger
 from caliscope import __root__
 from caliscope.calibration.capture_volume.helper_functions.get_point_estimates import (
     get_point_estimates,
 )
 from caliscope.calibration.capture_volume.point_estimates import PointEstimates
 from caliscope.calibration.charuco import Charuco
-from caliscope.cameras.camera_array import CameraData, CameraArray
-import cv2
-import pickle
+from caliscope.cameras.camera_array import CameraArray, CameraData
+
+logger = caliscope.logger.get(__name__)
 
 
 # Proceeding with basic idea that these functions will go into CaptureVolume.
 # so use capture_volume here which may just become self later on.
 
 
-def get_world_corners_xyz(
-    point_estimates: PointEstimates, sync_index: int
-) -> np.ndarray:
+def get_world_corners_xyz(point_estimates: PointEstimates, sync_index: int) -> np.ndarray:
     """
     returns the estimated x,y,z position of the board corners at the given sync index
     note that the array is ordered according to the charuco id
@@ -44,16 +44,12 @@ def get_world_corners_xyz(
 
     sorter = np.argsort(charuco_ids)
     # need to get charuco ids associated with the 3 point positions
-    unique_charuco_xyz_index = sorter[
-        np.searchsorted(charuco_ids, unique_charuco_id, sorter=sorter)
-    ]
+    unique_charuco_xyz_index = sorter[np.searchsorted(charuco_ids, unique_charuco_id, sorter=sorter)]
     world_corners_xyz = obj_xyz[unique_charuco_xyz_index]
     return world_corners_xyz
 
 
-def get_board_corners_xyz(
-    point_estimates: PointEstimates, sync_index: int, charuco: Charuco
-) -> np.ndarray:
+def get_board_corners_xyz(point_estimates: PointEstimates, sync_index: int, charuco: Charuco) -> np.ndarray:
     """
     Returns corner positions in board world (x,y,0) for the corners with estimated point
     coordinates at the give sync_index
@@ -68,9 +64,7 @@ def get_board_corners_xyz(
     return board_corners_xyz
 
 
-def get_anchor_cameras(
-    camera_array: CameraArray, point_estimates: PointEstimates, sync_index: int
-) -> list:
+def get_anchor_cameras(camera_array: CameraArray, point_estimates: PointEstimates, sync_index: int) -> list:
     """
     Returns the camera data objects that have an actual view of the board
     at the sync index and therefore can be used to estimate the pose from pnp
@@ -110,9 +104,7 @@ def get_rvec_tvec_from_board_pose(
             rvec=camera.rotation,
             tvec=camera.translation,
             cameraMatrix=camera.matrix,
-            distCoeffs=np.array(
-                [0, 0, 0, 0, 0], dtype=np.float32
-            ),  # because points are via bundle adj., no distortion
+            distCoeffs=np.array([0, 0, 0, 0, 0], dtype=np.float32),  # because points are via bundle adj., no distortion
         )
 
         # use solvepnp to estimate the pose of the camera relative to the board
@@ -129,9 +121,7 @@ def get_rvec_tvec_from_board_pose(
         # back into the shift in the world change of origin implied by the
         # pose of the camera relative to the board given its previous
         # pose in the old frame of reference
-        origin_shift_transform = np.matmul(
-            np.linalg.inv(camera.transformation), anchor_board_transform
-        )
+        origin_shift_transform = np.matmul(np.linalg.inv(camera.transformation), anchor_board_transform)
 
         rvec, tvec = transform_to_rvec_tvec(origin_shift_transform)
 
@@ -182,17 +172,13 @@ def rvec_tvec_to_transform(rvec: np.ndarray, tvec: np.ndarray) -> np.ndarray:
     return transform
 
 
-def world_board_distance(
-    tvec_xyz: np.ndarray, good_rvec: np.ndarray, raw_world_xyz, board_corners_xyz
-):
+def world_board_distance(tvec_xyz: np.ndarray, good_rvec: np.ndarray, raw_world_xyz, board_corners_xyz):
     scale = np.expand_dims(np.ones(raw_world_xyz.shape[0]), 1)
     raw_world_xyzh = np.hstack([raw_world_xyz, scale])
 
     origin_shift_transform = rvec_tvec_to_transform(good_rvec, tvec_xyz)
 
-    new_origin_xyzh = np.matmul(
-        np.linalg.inv(origin_shift_transform), raw_world_xyzh.T
-    ).T
+    new_origin_xyzh = np.matmul(np.linalg.inv(origin_shift_transform), raw_world_xyzh.T).T
     new_origin_xyz = new_origin_xyzh[:, 0:3]
 
     delta_xyz = new_origin_xyz - board_corners_xyz
@@ -236,15 +222,15 @@ def get_board_origin_transform(
 
 if __name__ == "__main__":
     #
-    from caliscope.session.session import LiveSession
-    from caliscope.cameras.camera_array_initializer import CameraArrayInitializer
     from caliscope.calibration.capture_volume.capture_volume import CaptureVolume
+    from caliscope.cameras.camera_array_initializer import CameraArrayInitializer
     from caliscope.gui.vizualize.calibration.capture_volume_visualizer import (
         CaptureVolumeVisualizer,
     )
     from caliscope.gui.vizualize.calibration.capture_volume_widget import (
         CaptureVolumeWidget,
     )
+    from caliscope.session.session import LiveSession
 
     # test_scenario = "4_cameras_nonoverlap"
     # test_scenario = "3_cameras_middle"
@@ -281,7 +267,7 @@ def get_board_origin_transform(
         camera_array = array_initializer.get_best_camera_array()
         point_estimates = get_point_estimates(camera_array, point_data_csv_path)
 
-        print(f"Optimizing initial camera array configuration ")
+        print("Optimizing initial camera array configuration ")
 
         capture_volume = CaptureVolume(camera_array, point_estimates)
         capture_volume._save(session_directory, "initial")
diff --git a/caliscope/calibration/charuco.py b/caliscope/calibration/charuco.py
index bc8a599d..807feab8 100644
--- a/caliscope/calibration/charuco.py
+++ b/caliscope/calibration/charuco.py
@@ -1,4 +1,4 @@
-#%%
+# %%
 
 # NOTE: Conversions are being made here between inches and cm because
 # this seems like a reasonable scale for discussing the board, but when
@@ -6,16 +6,20 @@
 # in meters as a standard convention of science, and to improve
 # readability of 3D positional output downstream
 
-import caliscope.logger
-
 from collections import defaultdict
 from itertools import combinations
+
 import cv2
 from PySide6.QtCore import Qt
 from PySide6.QtGui import QImage, QPixmap
+
+import caliscope.logger
+
 logger = caliscope.logger.get(__name__)
 
 INCHES_PER_CM = 0.393701
+
+
 class Charuco:
     """
     create a charuco board that can be printed out and used for camera
@@ -34,7 +38,6 @@ def __init__(
         square_size_overide_cm=None,
         inverted=False,
     ):  # after printing, measure actual and return to overide
-
         """
         Create board based on shape and dimensions
         square_size_overide_cm: correct for the actual printed size of the board
@@ -78,14 +81,12 @@ def dictionary_object(self):
     @property
     def board(self):
         if self.square_size_overide_cm:
-            square_length = self.square_size_overide_cm/100 # note: in cm within GUI
+            square_length = self.square_size_overide_cm / 100  # note: in cm within GUI
         else:
             board_height_m = self.board_height_cm / 100
             board_width_m = self.board_width_cm / 100
-            
-            square_length = min(
-                [board_height_m / self.rows, board_width_m / self.columns]
-            )
+
+            square_length = min([board_height_m / self.rows, board_width_m / self.columns])
         logger.info(f"Creating charuco with square length of {round(square_length,4)}")
 
         aruco_length = square_length * self.aruco_scale
@@ -119,9 +120,7 @@ def board_pixmap(self, width, height):
         rgb_image = cv2.cvtColor(self.board_img, cv2.COLOR_BGR2RGB)
         h, w, ch = rgb_image.shape
         bytes_per_line = ch * w
-        charuco_QImage = QImage(
-            rgb_image.data, w, h, bytes_per_line, QImage.Format.Format_RGB888
-        )
+        charuco_QImage = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format.Format_RGB888)
         p = charuco_QImage.scaled(
             width,
             height,
@@ -183,15 +182,11 @@ def get_object_corners(self, corner_ids):
         return self.board.chessboardCorners()[corner_ids, :]
 
     def summary(self):
-
         text = f"Columns: {self.columns}\n"
         text = text + f"Rows: {self.rows}\n"
-        text = (
-            text
-            + f"Board Size: {self.board_width} x {self.board_height} {self.units}\n"
-        )
+        text = text + f"Board Size: {self.board_width} x {self.board_height} {self.units}\n"
         text = text + f"Inverted:  {self.inverted}\n"
-        text = text + f"\n"
+        text = text + "\n"
         text = text + f"Square Edge Length: {self.square_size_overide_cm} cm"
         return text
 
@@ -223,12 +218,11 @@ def summary(self):
 
 
 if __name__ == "__main__":
-    charuco = Charuco(
-        4, 5, 4, 8.5, aruco_scale=0.75, units="inch",inverted=True, square_size_overide_cm=5.25)
+    charuco = Charuco(4, 5, 4, 8.5, aruco_scale=0.75, units="inch", inverted=True, square_size_overide_cm=5.25)
     charuco.save_image("test_charuco.png")
     width, height = charuco.board_img.shape
     logger.info(f"Board width is {width}\nBoard height is {height}")
-    
+
     corners = charuco.board.getChessboardCorners()
     logger.info(corners)
 
diff --git a/caliscope/calibration/draw_charuco.py b/caliscope/calibration/draw_charuco.py
index d5919deb..7a94a280 100644
--- a/caliscope/calibration/draw_charuco.py
+++ b/caliscope/calibration/draw_charuco.py
@@ -1,16 +1,20 @@
 # a set of helper functions meant to provide visual feedback
 # regarding the capture history and corner identification of
 # the charuco board
-import caliscope.logger
 from itertools import combinations
+
 import cv2
+
+import caliscope.logger
+
 logger = caliscope.logger.get(__name__)
 
+
 def grid_history(frame, ids, img_locs, connected_corners):
     """
     add the history of captured boards so that the user can see which ares of the camera FOV may not have data
     """
-    
+
     possible_pairs = {pair for pair in combinations(ids, 2)}
     connected_pairs = connected_corners.intersection(possible_pairs)
 
@@ -27,5 +31,3 @@ def grid_history(frame, ids, img_locs, connected_corners):
         cv2.line(frame, point_1, point_2, (255, 165, 0), 3)
 
     return frame
-
-
diff --git a/caliscope/calibration/intrinsic_calibrator.py b/caliscope/calibration/intrinsic_calibrator.py
index 68e0e3bf..d7aa2cf7 100644
--- a/caliscope/calibration/intrinsic_calibrator.py
+++ b/caliscope/calibration/intrinsic_calibrator.py
@@ -1,12 +1,13 @@
-import caliscope.logger
-from queue import Queue
-from threading import Thread, Event
 import random
+from queue import Queue
+from threading import Event, Thread
+
 import cv2
 
+import caliscope.logger
+from caliscope.cameras.camera_array import CameraData
 from caliscope.packets import FramePacket
 from caliscope.recording.recorded_stream import RecordedStream
-from caliscope.cameras.camera_array import CameraData
 
 logger = caliscope.logger.get(__name__)
 
@@ -26,18 +27,20 @@ def __init__(self, camera_data: CameraData, stream: RecordedStream):
         self.stream.subscribe(self.frame_packet_q)
 
         # The following group of parameters relate to the autopopulation of the calibrator
-        self.grid_history_q = Queue()  # for passing ids, img_loc used in calibration 
+        self.grid_history_q = Queue()  # for passing ids, img_loc used in calibration
         self.auto_store_data = Event()
         self.auto_store_data.clear()
-        self.auto_pop_frame_wait = 0  # how many frames will you hold ofF checking if the board can be added to the calibration pile.
+        self.auto_pop_frame_wait = (
+            0  # how many frames will you hold ofF checking if the board can be added to the calibration pile.
+        )
         self.target_grid_count = 0
 
         self.harvest_frames()
-         
+
     def harvest_frames(self):
         self.stop_event = Event()
         self.stop_event.clear()
-        
+
         def harvest_worker():
             while True:
                 frame_packet = self.frame_packet_q.get()
@@ -47,6 +50,7 @@ def harvest_worker():
                 self.add_frame_packet(frame_packet)
 
             logger.info(f"Harvest frames successfully ended in calibrator for port {self.stream.port}")
+
         self.harvest_thread = Thread(target=harvest_worker, args=[], daemon=True)
         self.harvest_thread.start()
 
@@ -70,7 +74,6 @@ def image_size(self):
         return image_size
 
     def initialize_point_history(self):
-
         # list of frame_indices that will go into the calibration
         self.calibration_frame_indices = []
 
@@ -91,12 +94,12 @@ def add_frame_packet(self, frame_packet: FramePacket):
             self.all_obj_loc[index] = frame_packet.points.obj_loc
 
             self.active_frame_index = index
-        
+
             # when auto store data is set, the stream should be pushing out all
             # frames consecutively from the beginning
             if self.auto_store_data.is_set():
                 point_id = frame_packet.points.point_id
-                
+
                 if point_id.size == 0:
                     corner_count = 0
                 else:
@@ -105,72 +108,72 @@ def add_frame_packet(self, frame_packet: FramePacket):
                 if self.auto_pop_frame_wait == 0 and corner_count >= self.threshold_corner_count:
                     # add frame to calibration data and reset the wait time
                     self.add_calibration_frame_index(index)
-                    self.auto_pop_frame_wait = self.wait_between 
+                    self.auto_pop_frame_wait = self.wait_between
                 else:
                     # count down to the next frame to consider autopopulating
-                    self.auto_pop_frame_wait = max(self.auto_pop_frame_wait-1,0)       
-                
+                    self.auto_pop_frame_wait = max(self.auto_pop_frame_wait - 1, 0)
+
                 logger.debug(f"Current index is {index}")
                 if index == self.stream.last_frame_index:
-                # end of stream, so stop auto pop and backfill to hit grid target
+                    # end of stream, so stop auto pop and backfill to hit grid target
                     logger.info("End of autopop detected...")
                     self.auto_store_data.clear()
                     self.backfill_calibration_frames()
 
-
     def backfill_calibration_frames(self):
-        logger.info(f"Initiating backfill of frames to hit target grid count of {self.target_grid_count}...currently at {self.grid_count}")
+        logger.info(
+            f"Initiating backfill of frames to hit target grid count of {self.target_grid_count}...currently at {self.grid_count}"  # noqa: E501
+        )
         actual_grid_count = len(self.calibration_frame_indices)
         logger.info(f"Actual Grid Count: {actual_grid_count}")
         # build new frame list
         new_potential_frames = []
         for frame_index, ids in self.all_ids.items():
             if frame_index not in self.calibration_frame_indices:
-                if len(ids) >= 6: # believe this may be a requirement of the calibration algorithm
+                if len(ids) >= 6:  # believe this may be a requirement of the calibration algorithm
                     new_potential_frames.append(frame_index)
-            
-        sample_size = self.target_grid_count-actual_grid_count
+
+        sample_size = self.target_grid_count - actual_grid_count
         sample_size = min(sample_size, len(new_potential_frames))
-        sample_size = max(sample_size,0)
+        sample_size = max(sample_size, 0)
 
-        random_frames = random.sample(new_potential_frames,sample_size)
+        random_frames = random.sample(new_potential_frames, sample_size)
         for frame in random_frames:
             self.add_calibration_frame_index(frame)
-        
+
     def add_calibration_frame_index(self, frame_index: int):
         """
         A "side effect" of this method is that the corner id and img_loc
         data is placed on a q. This q is consumed by the frame_emitter
         which will update the grid capture history based with those grids
 
-        This allows the GUI element (frame emitter) to stay in sync with the 
-        calibrator. 
+        This allows the GUI element (frame emitter) to stay in sync with the
+        calibrator.
         """
         logger.info(f"Adding frame data to calibration inputs for frame index {frame_index}")
         self.calibration_frame_indices.append(frame_index)
-        
+
         # Backchannel communication to frame_emitter to keep things aligned
         ids = self.all_ids[frame_index]
         img_loc = self.all_img_loc[frame_index]
-        self.grid_history_q.put((ids,img_loc))
-        
+        self.grid_history_q.put((ids, img_loc))
 
     def clear_calibration_data(self):
         logger.info("Clearing calibration data..")
         self.calibration_frame_indices = []
         self.set_calibration_inputs()
-        
-    def initiate_auto_pop(self, wait_between,threshold_corner_count, target_grid_count):
+
+    def initiate_auto_pop(self, wait_between, threshold_corner_count, target_grid_count):
         """
         This will enable actions within self.add_frame_packet
-        
+
         Now when frame_packets are read in from the stream, the
-        
+
         """
         logger.info(f"Initiating autopopulation of corner data in port {self.camera.port}")
         self.clear_calibration_data()
         self.wait_between = wait_between
-        self.threshold_corner_count = threshold_corner_count        
+        self.threshold_corner_count = threshold_corner_count
         self.target_grid_count = target_grid_count
         self.initialize_point_history()
         self.auto_store_data.set()
@@ -193,7 +196,9 @@ def set_calibration_inputs(self):
                 self.calibration_img_loc.append(self.all_img_loc[index])
                 self.calibration_obj_loc.append(self.all_obj_loc[index])
             else:
-                logger.info(f"Note that empty data stored in frame index {index}. This is not being used in the calibration")
+                logger.info(
+                    f"Note that empty data stored in frame index {index}. This is not being used in the calibration"
+                )
         logger.info(f"Total size of inputs is {len(self.calibration_point_ids)}")
 
     def calibrate_camera(self):
diff --git a/caliscope/calibration/stereocalibrator.py b/caliscope/calibration/stereocalibrator.py
index 6c1afaa1..d81f8043 100644
--- a/caliscope/calibration/stereocalibrator.py
+++ b/caliscope/calibration/stereocalibrator.py
@@ -1,11 +1,13 @@
+from itertools import combinations
 from pathlib import Path
-import caliscope.logger
+
 import cv2
-import pandas as pd
-from caliscope import __root__
 import numpy as np
+import pandas as pd
 import rtoml
-from itertools import combinations
+
+import caliscope.logger
+from caliscope import __root__
 
 logger = caliscope.logger.get(__name__)
 
@@ -23,8 +25,6 @@ def __init__(
         # set ports keeping in mind that something may be flagged for ignore
         for key, value in self.config.items():
             if key[0:4] == "cam_":
-                # NOTE: Commenting out this line as "ignore" was only a property needed when managing webcams but does not make sense here
-                # if not self.config[key]["ignore"]:
                 self.ports.append(int(key[4:]))
 
         # import point data, adding coverage regions to each port
@@ -68,12 +68,8 @@ def get_coverage_region(row, ports):
             get_coverage_region, axis=1, args=(self.ports,)
         )
 
-        points_w_pivoted_ports = points_w_pivoted_ports.filter(
-            ["sync_index", "point_id", "coverage_region"]
-        )
-        points_w_regions = point_data.merge(
-            points_w_pivoted_ports, "left", ["sync_index", "point_id"]
-        )
+        points_w_pivoted_ports = points_w_pivoted_ports.filter(["sync_index", "point_id", "coverage_region"])
+        points_w_regions = point_data.merge(points_w_pivoted_ports, "left", ["sync_index", "point_id"])
 
         return points_w_regions
 
@@ -95,9 +91,7 @@ def get_boards_with_coverage(self):
 
         # find the primary region each board is in, then merge in total counts
         all_boards = (
-            self.all_point_data.filter(
-                ["port", "sync_index", "point_id", "coverage_region"]
-            )
+            self.all_point_data.filter(["port", "sync_index", "point_id", "coverage_region"])
             .groupby(["port", "sync_index", "coverage_region"])
             .agg({"point_id": "count"})
             .reset_index()
@@ -115,16 +109,12 @@ def get_boards_with_coverage(self):
             .reset_index()
             .rename(columns={"coverage_region": "primary_coverage_region"})
             .drop("point_count", axis=1)  # no longer means anthing
-            .merge(
-                board_points, "left", ["port", "sync_index"]
-            )  # merge in a point_count that means something
+            .merge(board_points, "left", ["port", "sync_index"])  # merge in a point_count that means something
         )
 
         return all_boards
 
-    def get_stereopair_data(
-        self, pair: tuple, boards_sampled: int, random_state=1
-    ) -> pd.DataFrame or None:
+    def get_stereopair_data(self, pair: tuple, boards_sampled: int, random_state=1) -> pd.DataFrame or None:
         # convenience function to get the points that are in the overlap regions of the pairs
         def in_pair(row: int, pair: tuple):
             """
@@ -136,18 +126,14 @@ def in_pair(row: int, pair: tuple):
 
             a, b = str(a), str(b)
 
-            region_check = ("_" + a + "_") in row.coverage_region and (
-                "_" + b + "_"
-            ) in row.coverage_region
+            region_check = ("_" + a + "_") in row.coverage_region and ("_" + b + "_") in row.coverage_region
             return region_check and port_check
 
         # flag the points that belong to the pair overlap regions
-        self.all_point_data["in_pair"] = self.all_point_data.apply(
-            in_pair, axis=1, args=(pair,)
-        )
+        self.all_point_data["in_pair"] = self.all_point_data.apply(in_pair, axis=1, args=(pair,))
 
         # group points into boards and get the total count for sample weighting below
-        pair_points = self.all_point_data[self.all_point_data["in_pair"] == True]
+        pair_points = self.all_point_data[self.all_point_data["in_pair"]]
         pair_boards = (
             pair_points.filter(["sync_index", "port", "point_id"])
             .groupby(["sync_index", "port"])
@@ -169,13 +155,9 @@ def in_pair(row: int, pair: tuple):
             sample_weight = pair_boards["point_count"] ** 2
 
             # get the randomly selected subset
-            selected_boards = pair_boards.sample(
-                n=sample_size, weights=sample_weight, random_state=random_state
-            )
+            selected_boards = pair_boards.sample(n=sample_size, weights=sample_weight, random_state=random_state)
 
-            selected_pair_points = pair_points.merge(
-                selected_boards, "right", "sync_index"
-            )
+            selected_pair_points = pair_points.merge(selected_boards, "right", "sync_index")
         else:
             logger.info(f"For pair {pair} there are no shared boards")
             selected_pair_points = None
@@ -210,9 +192,7 @@ def stereo_calibrate_all(self, boards_sampled=10):
                 self.config[config_key]["translation"] = translation
                 self.config[config_key]["RMSE"] = error
 
-        logger.info(
-            "Direct stereocalibration complete for all pairs for which data is available"
-        )
+        logger.info("Direct stereocalibration complete for all pairs for which data is available")
         logger.info(f"Saving stereo-pair extrinsic data to {self.config_path}")
         with open(self.config_path, "w") as f:
             rtoml.dump(self.config, f)
@@ -224,12 +204,8 @@ def stereo_calibrate(self, pair, boards_sampled=10):
         paired_point_data = self.get_stereopair_data(pair, boards_sampled)
 
         if paired_point_data is not None:
-            img_locs_A, obj_locs_A = self.get_stereocal_inputs(
-                pair[0], paired_point_data
-            )
-            img_locs_B, obj_locs_B = self.get_stereocal_inputs(
-                pair[1], paired_point_data
-            )
+            img_locs_A, obj_locs_A = self.get_stereocal_inputs(pair[0], paired_point_data)
+            img_locs_B, obj_locs_B = self.get_stereocal_inputs(pair[1], paired_point_data)
 
             camera_matrix_A = self.config["cam_" + str(pair[0])]["matrix"]
             camera_matrix_B = self.config["cam_" + str(pair[1])]["matrix"]
@@ -259,7 +235,9 @@ def stereo_calibrate(self, pair, boards_sampled=10):
                 distortion_A,
                 camera_matrix_B,
                 distortion_B,
-                imageSize=None,  # this does not matter. from OpenCV: "Size of the image used only to initialize the camera intrinsic matrices."
+                # imageSize does not matter.
+                # from OpenCV: "Size of the image used only to initialize the camera intrinsic matrices."
+                imageSize=None,
                 criteria=criteria,
                 flags=stereocalibration_flags,
             )
diff --git a/caliscope/cameras/camera.py b/caliscope/cameras/camera.py
index 24c1623d..6eaa05e4 100644
--- a/caliscope/cameras/camera.py
+++ b/caliscope/cameras/camera.py
@@ -14,14 +14,16 @@
 #   - distortion parameters
 #
 # New camera configurations
-#%%
+# %%
 
+import os
 import platform
 import time
-import os
 
 import cv2
+
 import caliscope.logger
+
 logger = caliscope.logger.get(__name__)
 
 TEST_FRAME_COUNT = 10
@@ -30,23 +32,21 @@
 
 
 class Camera:
-
     # https://docs.opencv.org/3.4/d4/d15/group__videoio__flags__base.html
     # see above for constants used to access properties
-    def __init__(self, port, verified_resolutions = None, connect_API = None):
-
+    def __init__(self, port, verified_resolutions=None, connect_API=None):
         if connect_API is not None:
             self.connect_API = connect_API
         else:
-            if os.name == 'nt': #windows
+            if os.name == "nt":  # windows
                 self.connect_API = cv2.CAP_DSHOW
-            else: # UNIX variant
+            else:  # UNIX variant
                 self.connect_API = cv2.CAP_ANY
 
         # check if source has a data feed before proceeding...if not it is
         # either in use or fake
         logger.info(f"Attempting to connect video capture at port {port}")
-        test_capture = cv2.VideoCapture(port,self.connect_API)
+        test_capture = cv2.VideoCapture(port, self.connect_API)
         for _ in range(0, TEST_FRAME_COUNT):
             good_read, frame = test_capture.read()
 
@@ -56,19 +56,19 @@ def __init__(self, port, verified_resolutions = None, connect_API = None):
             self.port = port
             self.capture = test_capture
             self.active_port = True
+
             # limit buffer size so that you are always reading the latest frame
-            self.capture.set(
-                cv2.CAP_PROP_BUFFERSIZE, 1
-            )  # from https://stackoverflow.com/questions/58293187/opencv-real-time-streaming-video-capture-is-slow-how-to-drop-frames-or-getanother thread signaled a change to mediapipe overley-sync
+            # from https://stackoverflow.com/questions/58293187/opencv-real-time-streaming-video-capture-is-slow-how-to-drop-frames-or-getanother thread signaled a change to mediapipe overley-sync  # noqa: E501
+            self.capture.set(cv2.CAP_PROP_BUFFERSIZE, 1)
 
-            self.ignore = False # flag camera during single camera setup to be ignored in the future
+            self.ignore = False  # flag camera during single camera setup to be ignored in the future
 
             # sets orientation in the GUI, but otherwise does not affect the frame
             self.rotation_count = 0  # +1 for each 90 degree CW rotation, -1 for CCW
 
             self.set_exposure()
             self.set_default_resolution()
-        else: 
+        else:
             # probably busy
             logger.info(f"Camera at port {port} appears to be busy")
             self.port = port
@@ -77,7 +77,7 @@ def __init__(self, port, verified_resolutions = None, connect_API = None):
             raise Exception(f"Not reading at port {port}...likely in use")
 
         # Test to see if camera is virtual
-        spoof_resolution = (599,599)
+        spoof_resolution = (599, 599)
         self.size = spoof_resolution
         if self.size == spoof_resolution:
             self.virtual_camera = True
@@ -113,9 +113,9 @@ def exposure(self, value):
         """Note that OpenCV appears to change the exposure value, but
         this is not read back accurately through the getter, so just
         track it manually after updating"""
-        if platform.system()=="Windows":
+        if platform.system() == "Windows":
             self.capture.set(cv2.CAP_PROP_EXPOSURE, value)
-        
+
         else:
             self.capture.set(cv2.CAP_PROP_IOS_DEVICE_EXPOSURE, value)
 
@@ -174,11 +174,10 @@ def set_possible_resolutions(self):
             # attempt to set the camera to the given resolution
             logger.info(f"Checking resolution of {resolution} at port {self.port}")
             self.size = resolution
-            
+
             # if it sticks, then that resolution is verified
             if resolution == self.size:
                 self.verified_resolutions.append(resolution)
-                
 
     def rotate_CW(self):
         if self.rotation_count == 3:
@@ -207,16 +206,9 @@ def calibration_summary(self):
         if self.error and self.error != "NA":
             error_text = f"Error:\t{round(self.error,3)} "
             cam_matrix_text = "Camera Matrix:\n" + (
-                "\n".join(
-                    [
-                        "\t".join([str(round(float(cell), 1)) for cell in row])
-                        for row in self.matrix
-                    ]
-                )
-            )
-            distortion_text = "Distortion:\t" + ",".join(
-                [str(round(float(cell), 2)) for cell in self.distortions]
+                "\n".join(["\t".join([str(round(float(cell), 1)) for cell in row]) for row in self.matrix])
             )
+            distortion_text = "Distortion:\t" + ",".join([str(round(float(cell), 2)) for cell in self.distortions])
 
             # print(self.camera_matrix)
             summary = (
@@ -234,6 +226,7 @@ def calibration_summary(self):
         else:
             return "No Calibration Stored"
 
+
 # common possibilities taken from https://en.wikipedia.org/wiki/List_of_common_resolutions
 RESOLUTIONS_TO_CHECK = [
     # (352, 240),
@@ -263,8 +256,7 @@ def calibration_summary(self):
 
 ######################### TEST FUNCTIONALITY OF CAMERAS ########################
 if __name__ == "__main__":
-
-    cam = Camera(4, verified_resolutions=[(640,480), (1280,720)])
+    cam = Camera(4, verified_resolutions=[(640, 480), (1280, 720)])
     logger.info(f"Camera {cam.port} has possible resolutions: {cam.verified_resolutions}")
 
     for res in cam.verified_resolutions:
@@ -276,7 +268,7 @@ def calibration_summary(self):
         logger.info(f"Setting camera size to {res}")
         cam.size = res
         logger.info("Resolution successfully updated...")
-            
+
         while True:
             success, frame = cam.capture.read()
             cv2.imshow(f"Resolution: {res}; press 'q' to move to next resolution", frame)
@@ -291,26 +283,26 @@ def calibration_summary(self):
     #     time.sleep(.01)
 
     exposure_test_started = False
-    
+
     start_time = time.perf_counter()
-    
+
     while True:
         success, frame = cam.capture.read()
-        elapsed_seconds = int(time.perf_counter()-start_time)
+        elapsed_seconds = int(time.perf_counter() - start_time)
         logger.debug(f"{elapsed_seconds} seconds have elapsed since loop began")
 
         cv2.imshow("Exposure Test", frame)
-       
-        cam.exposure = -10+elapsed_seconds 
-         
+
+        cam.exposure = -10 + elapsed_seconds
+
         if cv2.waitKey(1) == ord("q"):
             cam.disconnect()
             cv2.destroyAllWindows()
-            break     
-        
+            break
+
         if elapsed_seconds > 10:
             cam.disconnect()
             cv2.destroyAllWindows()
-            break 
+            break
 
 # %%
diff --git a/caliscope/cameras/camera_array.py b/caliscope/cameras/camera_array.py
index 2eda53a9..112d684f 100644
--- a/caliscope/cameras/camera_array.py
+++ b/caliscope/cameras/camera_array.py
@@ -1,16 +1,18 @@
 # %%
 
-import caliscope.logger
-
-import numpy as np
+from collections import OrderedDict
 from dataclasses import dataclass
+
 import cv2
-from enum import Enum, auto
+import numpy as np
 from numba.typed import Dict
-from collections import OrderedDict
+
+import caliscope.logger
+
 logger = caliscope.logger.get(__name__)
 CAMERA_PARAM_COUNT = 6
 
+
 @dataclass
 class CameraData:
     """
@@ -21,37 +23,37 @@ class CameraData:
 
     port: int
     size: tuple
-    rotation_count: int=0
-    error: float=None  # the RMSE of reprojection associated with the intrinsic calibration
-    matrix: np.ndarray=None
-    distortions: np.ndarray=None  #
-    exposure: int=None
-    grid_count: int=None
-    ignore: bool=False
-    verified_resolutions: np.ndarray=None
-    translation: np.ndarray =None # camera relative to world
-    rotation: np.ndarray = None# camera relative to world
+    rotation_count: int = 0
+    error: float = None  # the RMSE of reprojection associated with the intrinsic calibration
+    matrix: np.ndarray = None
+    distortions: np.ndarray = None  #
+    exposure: int = None
+    grid_count: int = None
+    ignore: bool = False
+    verified_resolutions: np.ndarray = None
+    translation: np.ndarray = None  # camera relative to world
+    rotation: np.ndarray = None  # camera relative to world
 
     @property
     def transformation(self):
-        """"
-        Rotation and transformation combined to allow 
+        """ "
+        Rotation and transformation combined to allow
         """
-        
+
         t = np.hstack([self.rotation, np.expand_dims(self.translation, 1)])
-        t = np.vstack([t, np.array([0,0,0,1], np.float32)])
-        return t 
-   
-    @transformation.setter 
+        t = np.vstack([t, np.array([0, 0, 0, 1], np.float32)])
+        return t
+
+    @transformation.setter
     def transformation(self, t: np.ndarray):
-        self.rotation = t[0:3,0:3]
-        self.translation = t[0:3,3]
+        self.rotation = t[0:3, 0:3]
+        self.translation = t[0:3, 3]
         logger.info(f"Rotation and Translation being updated to {self.rotation} and {self.translation}")
-    
-    @property  
+
+    @property
     def projection_matrix(self):
-        return self.matrix @ self.transformation[0:3,:]
-         
+        return self.matrix @ self.transformation[0:3, :]
+
     def extrinsics_to_vector(self):
         """
         Converts camera parameters to a numpy vector for use with bundle adjustment.
@@ -71,8 +73,7 @@ def extrinsics_from_vector(self, row):
         self.rotation = cv2.Rodrigues(row[0:3])[0]
         self.translation = np.array([row[3:6]], dtype=np.float64)[0]
 
-    def get_display_data(self)-> OrderedDict:
-        
+    def get_display_data(self) -> OrderedDict:
         # Extracting camera matrix parameters
         # self.matrix = None
         if self.matrix is not None:
@@ -81,7 +82,6 @@ def get_display_data(self)-> OrderedDict:
         else:
             fx, fy = None, None
             cx, cy = None, None
-            
 
         # Extracting distortion coefficients
         if self.distortions is not None:
@@ -89,36 +89,47 @@ def get_display_data(self)-> OrderedDict:
         else:
             k1, k2, p1, p2, k3 = None, None, None, None, None
 
-        def round_or_none(value,places):
+        def round_or_none(value, places):
             if value is None:
                 return None
             else:
-                return round(value,places)
-            
+                return round(value, places)
+
         # Creating the dictionary with OrderedDict
-        camera_display_dict = OrderedDict([
-            ("size", self.size),
-            ("RMSE", self.error),
-            ("Grid_Count", self.grid_count),
-            ("rotation_count", self.rotation_count),
-            ("intrinsic_parameters", OrderedDict([
-                ("focal_length_x", round_or_none(fx,2)),
-                ("focal_length_y", round_or_none(fy,2)),
-                ("optical_center_x", round_or_none(cx,2)),
-                ("optical_center_y", round_or_none(cy,2))
-            ])),
-            ("distortion_coefficients", OrderedDict([
-                ("radial_k1", round_or_none(k1,2)),
-                ("radial_k2", round_or_none(k2,2)),
-                ("radial_k3", round_or_none(k3,2)),
-                ("tangential_p1", round_or_none(p1,2)),
-                ("tangential_p2", round_or_none(p2,2))
-            ]))
-        ])
+        camera_display_dict = OrderedDict(
+            [
+                ("size", self.size),
+                ("RMSE", self.error),
+                ("Grid_Count", self.grid_count),
+                ("rotation_count", self.rotation_count),
+                (
+                    "intrinsic_parameters",
+                    OrderedDict(
+                        [
+                            ("focal_length_x", round_or_none(fx, 2)),
+                            ("focal_length_y", round_or_none(fy, 2)),
+                            ("optical_center_x", round_or_none(cx, 2)),
+                            ("optical_center_y", round_or_none(cy, 2)),
+                        ]
+                    ),
+                ),
+                (
+                    "distortion_coefficients",
+                    OrderedDict(
+                        [
+                            ("radial_k1", round_or_none(k1, 2)),
+                            ("radial_k2", round_or_none(k2, 2)),
+                            ("radial_k3", round_or_none(k3, 2)),
+                            ("tangential_p1", round_or_none(p1, 2)),
+                            ("tangential_p2", round_or_none(p2, 2)),
+                        ]
+                    ),
+                ),
+            ]
+        )
 
         return camera_display_dict
 
-
     def erase_calibration_data(self):
         self.error = None
         self.matrix = None
@@ -126,7 +137,8 @@ def erase_calibration_data(self):
         self.grid_count = None
         self.translation = None
         self.rotation = None
-        
+
+
 @dataclass
 class CameraArray:
     """The plan is that this will expand to become an interface for setting the origin.
@@ -138,21 +150,21 @@ class CameraArray:
     def port_index(self):
         """
         Provides a dictionary mapping the camera port to an index. Generally,this
-        will match the camera ports 1:1, but will be different when a camera 
+        will match the camera ports 1:1, but will be different when a camera
         is being ignored. Used to manage reference to camera parameters in xy_reprojection_error
-        used within the least_squares optimization of the capture volume. 
+        used within the least_squares optimization of the capture volume.
         """
         not_ignored_ports = [port for port, cam in self.cameras.items() if not cam.ignore]
         not_ignored_ports.sort()
         not_ignored_indices = [i for i in range(len(not_ignored_ports))]
-        port_indices = {port:i for port, i in zip(not_ignored_ports,not_ignored_indices)}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
-        
+        port_indices = {port: i for port, i in zip(not_ignored_ports, not_ignored_indices)}
+
         return port_indices
-   
-    @property 
+
+    @property
     def index_port(self):
         return {value: key for key, value in self.port_index.items()}
-    
+
     def get_extrinsic_params(self):
         """for each camera build the CAMERA_PARAM_COUNT element parameter index
         camera_params with shape (n_cameras, CAMERA_PARAM_COUNT)
@@ -175,8 +187,7 @@ def get_extrinsic_params(self):
 
         return camera_params
 
-    def update_extrinsic_params(self, least_sq_result_x:np.array):
-
+    def update_extrinsic_params(self, least_sq_result_x: np.array):
         n_cameras = len(self.port_index)
         n_cam_param = 6  # 6 DoF
         flat_camera_params = least_sq_result_x[0 : n_cameras * n_cam_param]
@@ -187,29 +198,28 @@ def update_extrinsic_params(self, least_sq_result_x:np.array):
             port = self.index_port[index]  # correct in case ignoring a camera
             cam_vec = new_camera_params[index, :]
             self.cameras[port].extrinsics_from_vector(cam_vec)
-        
-    def all_extrinsics_calibrated(self)->bool:
+
+    def all_extrinsics_calibrated(self) -> bool:
         # assume extrinsics calibrated and provide otherwise
-        full_extrinsics = True 
+        full_extrinsics = True
         for port, cam in self.cameras.items():
             if cam.rotation is None or cam.translation is None:
                 full_extrinsics = False
         return full_extrinsics
-   
-    def all_intrinsics_calibrated(self)->bool:
+
+    def all_intrinsics_calibrated(self) -> bool:
         # assume true and prove false
         full_intrinsics = True
         for port, cam in self.cameras.items():
             if cam.matrix is None or cam.distortions is None:
                 full_intrinsics = False
         return full_intrinsics
-    
+
     @property
-    def projection_matrices(self) -> Dict: 
+    def projection_matrices(self) -> Dict:
         logger.info("Creating camera array projection matrices")
         proj_mat = Dict()
         for port, cam in self.cameras.items():
             proj_mat[port] = cam.projection_matrix
-        
+
         return proj_mat
-            
diff --git a/caliscope/cameras/camera_array_initializer.py b/caliscope/cameras/camera_array_initializer.py
index ea5fa963..1ff31c79 100644
--- a/caliscope/cameras/camera_array_initializer.py
+++ b/caliscope/cameras/camera_array_initializer.py
@@ -1,20 +1,22 @@
 # %%
 
 
+from dataclasses import dataclass
+from itertools import permutations
 from pathlib import Path
-from caliscope.cameras.camera_array import CameraData, CameraArray
-from caliscope.calibration.capture_volume.point_estimates import PointEstimates
+
+import numpy as np
+import rtoml
+
+import caliscope.logger
+from caliscope import __root__
 from caliscope.calibration.capture_volume.capture_volume import CaptureVolume
 from caliscope.calibration.capture_volume.helper_functions.get_point_estimates import (
     get_point_estimates,
 )
+from caliscope.calibration.capture_volume.point_estimates import PointEstimates
+from caliscope.cameras.camera_array import CameraArray, CameraData
 
-from itertools import permutations
-from caliscope import __root__
-import numpy as np
-from dataclasses import dataclass, asdict
-import rtoml
-import caliscope.logger
 logger = caliscope.logger.get(__name__)
 
 
@@ -42,7 +44,6 @@ def pair(self):
 
     @property
     def transformation(self):
-
         R_stack = np.vstack([self.rotation, np.array([0, 0, 0])])
         t_stack = np.vstack([self.translation, np.array([1])])
         Tranformation = np.hstack([R_stack, t_stack])
@@ -67,9 +68,8 @@ def get_inverted_stereopair(stereo_pair: StereoPair) -> StereoPair:
     )
     return inverted_stereopair
 
-def get_bridged_stereopair(
-    pair_A_B: StereoPair, pair_B_C: StereoPair
-) -> StereoPair:
+
+def get_bridged_stereopair(pair_A_B: StereoPair, pair_B_C: StereoPair) -> StereoPair:
     port_A = pair_A_B.primary_port
     port_C = pair_B_C.secondary_port
 
@@ -79,9 +79,7 @@ def get_bridged_stereopair(
 
     # new transformations are added on the left
     # https://youtube.com/watch?v=q0mRtuiKSKg&feature=shares&t=66
-    bridged_transformation = np.matmul(
-        pair_B_C.transformation, pair_A_B.transformation
-    )
+    bridged_transformation = np.matmul(pair_B_C.transformation, pair_A_B.transformation)
     bridged_rotation = bridged_transformation[0:3, 0:3]
     bridged_translation = bridged_transformation[None, 0:3, 3].T
 
@@ -92,13 +90,12 @@ def get_bridged_stereopair(
         translation=bridged_translation,
         rotation=bridged_rotation,
     )
-        
+
     return stereo_A_C
 
 
 class CameraArrayInitializer:
     def __init__(self, config_path: Path):
-
         logger.info("Creating initial estimate of camera array based on stereopairs...")
 
         self.config = rtoml.load(config_path)
@@ -112,28 +109,26 @@ def _fill_stereopair_gaps(self):
         Loop across missing pairs and create bridged stereopairs when possible.
         It may be that one iteration is not sufficient to fill all missing pairs,
         so iterate until no more missing pairs...
-        
+
         The code below uses a naming convention to describe the relationship between
         two stereo pairs (A,X) and (X,C) that can be used to build a bridge stereopair (A,C)
         """
 
         # fill with dummy value to get the loop running
         missing_count_last_cycle = -1
-        
+
         while len(self._get_missing_stereopairs()) != missing_count_last_cycle:
-            
             # prep the variable. if it doesn't go down, terminate
             missing_count_last_cycle = len(self._get_missing_stereopairs())
 
             for pair in self._get_missing_stereopairs():
-             
                 port_A = pair[0]
                 port_C = pair[1]
-    
+
                 # get lists of all the estimiated stereopairs that might bridge across test_missing
-                all_pairs_A_X = [pair for pair in self.estimated_stereopairs.keys() if pair[0]==port_A]
-                all_pairs_X_C = [pair for pair in self.estimated_stereopairs.keys() if pair[1]==port_C]
-   
+                all_pairs_A_X = [pair for pair in self.estimated_stereopairs.keys() if pair[0] == port_A]
+                all_pairs_X_C = [pair for pair in self.estimated_stereopairs.keys() if pair[1] == port_C]
+
                 stereopair_A_C = None
 
                 for pair_A_X in all_pairs_A_X:
@@ -159,12 +154,11 @@ def _fill_stereopair_gaps(self):
             raise ValueError("Insufficient stereopairs to allow array to be estimated")
 
     def _get_missing_stereopairs(self):
-
-        possible_stereopairs = [pair for pair in permutations(self.ports,2)]
+        possible_stereopairs = [pair for pair in permutations(self.ports, 2)]
         missing_stereopairs = [pair for pair in possible_stereopairs if pair not in self.estimated_stereopairs.keys()]
 
         return missing_stereopairs
-        
+
     def _get_ports(self) -> list:
         ports = []
         for key, params in self.config.items():
@@ -179,7 +173,6 @@ def _get_ports(self) -> list:
         return ports
 
     def _get_captured_stereopairs(self) -> dict:
-
         stereopairs = {}
 
         # Create StereoPair objects for each saved stereocalibration output in config
@@ -230,9 +223,9 @@ def _get_scored_anchored_array(self, anchor_port: int) -> tuple:
         total_error_score = 0
 
         for key, data in self.config.items():
-            # NOTE: commenting out second conditional check below. If you come back to this in a month and 
+            # NOTE: commenting out second conditional check below. If you come back to this in a month and
             # things haven't been breaking, then just delete all these comments.
-            if key.startswith("cam_"): # and not self.config[key]["ignore"]:
+            if key.startswith("cam_"):  # and not self.config[key]["ignore"]:
                 port = data["port"]
                 size = data["size"]
                 rotation_count = data["rotation_count"]
@@ -247,9 +240,7 @@ def _get_scored_anchored_array(self, anchor_port: int) -> tuple:
                 # update with extrinsics, though place anchor camera at origin
                 if port == anchor_port:
                     translation = np.array([0, 0, 0], dtype=np.float64).T
-                    rotation = np.array(
-                        [[1, 0, 0], [0, 1, 0], [0, 0, 1]], dtype=np.float64
-                    )
+                    rotation = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]], dtype=np.float64)
                 else:
                     anchored_stereopair = self.estimated_stereopairs[(anchor_port, port)]
                     translation = anchored_stereopair.translation[:, 0]
@@ -299,24 +290,22 @@ def get_best_camera_array(self):
 
         return best_initial_array
 
-    def add_stereopair(self, stereopair:StereoPair):
+    def add_stereopair(self, stereopair: StereoPair):
         self.estimated_stereopairs[stereopair.pair] = stereopair
         inverted_stereopair = get_inverted_stereopair(stereopair)
         self.estimated_stereopairs[inverted_stereopair.pair] = inverted_stereopair
-        
+
 
 # def get_anchored_pairs(anchor: int, all_stereopairs:dict)->dict:
 
 
 if __name__ == "__main__":
-
     session_directory = Path(__root__, "tests", "sessions", "217")
 
     config_path = Path(session_directory, "config.toml")
 
     initializer = CameraArrayInitializer(config_path)
-        
-    
+
     camera_array = initializer.get_best_camera_array()
 
     extrinsic_calibration_xy = Path(session_directory, "point_data.csv")
@@ -334,5 +323,4 @@ def add_stereopair(self, stereopair:StereoPair):
     # capture_volume.optimize()
 
 
-
 # %%
diff --git a/caliscope/cameras/synchronizer.py b/caliscope/cameras/synchronizer.py
index bb47812f..338d1988 100644
--- a/caliscope/cameras/synchronizer.py
+++ b/caliscope/cameras/synchronizer.py
@@ -1,27 +1,24 @@
-import caliscope.logger
-
-
 # logger.setLevel(logging.DEBUG)
-
 import time
 from queue import Queue
-from threading import Thread, Event
+from threading import Event, Thread
 
 import numpy as np
+
+import caliscope.logger
 from caliscope.packets import SyncPacket
 
 logger = caliscope.logger.get(__name__)
 
-DROPPED_FRAME_TRACK_WINDOW = 100 # trailing frames tracked for reporting purposes
+DROPPED_FRAME_TRACK_WINDOW = 100  # trailing frames tracked for reporting purposes
+
 
 class Synchronizer:
     def __init__(self, streams: dict):
         self.streams = streams
         self.current_synched_frames = None
 
-        self.synched_frames_subscribers = (
-            []
-        )  # queues that will receive actual frame data
+        self.synched_frames_subscribers = []  # queues that will receive actual frame data
 
         self.all_frame_packets = {}
         self.stop_event = Event()
@@ -34,38 +31,37 @@ def __init__(self, streams: dict):
             q = Queue(-1)
             self.frame_packet_queues[port] = q
 
-        self.subscribed_to_streams = False # not subscribed yet
+        self.subscribed_to_streams = False  # not subscribed yet
         self.subscribe_to_streams()
 
         # note that self.fps target is set in set_stream_fps
         # self.set_stream_fps(fps_target)
         # self.fps_mean = fps_target
-        
+
         # place to store a recent history of dropped frames
-        self.dropped_frame_history = {port:[] for port in sorted(self.ports)} 
-        
+        self.dropped_frame_history = {port: [] for port in sorted(self.ports)}
+
         self.initialize_ledgers()
         self.start()
 
-    def set_tracking_on_streams(self, track:bool):
+    def set_tracking_on_streams(self, track: bool):
         for port, stream in self.streams.items():
             stream.set_tracking_on(track)
-    
+
     def update_dropped_frame_history(self):
-        current_dropped:dict = self.current_sync_packet.dropped    
-        
+        current_dropped: dict = self.current_sync_packet.dropped
+
         for port, dropped in current_dropped.items():
             self.dropped_frame_history[port].append(dropped)
             self.dropped_frame_history[port] = self.dropped_frame_history[port][-DROPPED_FRAME_TRACK_WINDOW:]
 
-    @property 
+    @property
     def dropped_fps(self):
         """
         Averages dropped frame count across the observed history
         """
-        return {port:np.mean(drop_history) for port,drop_history in self.dropped_frame_history.items()}        
+        return {port: np.mean(drop_history) for port, drop_history in self.dropped_frame_history.items()}
 
-        
     # def set_stream_fps(self, fps_target):
     #     self.fps_target = fps_target
     #     logger.info(f"Attempting to change target fps in streams to {fps_target}")
@@ -91,13 +87,11 @@ def stop(self):
             t.join()
 
     def initialize_ledgers(self):
-
         self.port_frame_count = {port: 0 for port in self.ports}
         self.port_current_frame = {port: 0 for port in self.ports}
         self.mean_frame_times = []
 
     def start(self):
-
         logger.info("About to submit Threadpool of frame Harvesters")
         self.threads = []
         for port, stream in self.streams.items():
@@ -110,7 +104,6 @@ def start(self):
         self.thread = Thread(target=self.synch_frames_worker, args=(), daemon=True)
         self.thread.start()
 
-
     def subscribe_to_sync_packets(self, q):
         logger.info("Adding queue to receive synched frames")
         self.synched_frames_subscribers.append(q)
@@ -132,7 +125,7 @@ def harvest_frame_packets(self, stream):
             self.port_frame_count[port] += 1
 
             logger.debug(
-                f"Frame data harvested from reel {frame_packet.port} with index {frame_index} and frame time of {frame_packet.frame_time}"
+                f"Frame data harvested from reel {frame_packet.port} with index {frame_index} and frame time of {frame_packet.frame_time}"  # noqa E501
             )
 
         logger.info(f"Frame harvester for port {port} completed")
@@ -148,24 +141,20 @@ def earliest_next_frame(self, port):
 
             # problem with outpacing the threads reading data in, so wait if need be
             while frame_data_key not in self.all_frame_packets.keys():
-                logger.debug(
-                    f"Waiting in a loop for frame data to populate with key: {frame_data_key}"
-                )
+                logger.debug(f"Waiting in a loop for frame data to populate with key: {frame_data_key}")
                 if self.subscribed_to_streams:
                     time.sleep(0.1)
                 else:
                     # provide infrequent updates of busy waiting
-                    if int(time.time()) % 10 ==0:
+                    if int(time.time()) % 10 == 0:
                         logger.info("Synchronizer not subscribed to any streams and busy waiting...")
                     time.sleep(1)
-                    
+
             next_frame_time = self.all_frame_packets[frame_data_key].frame_time
 
             if next_frame_time == -1:
-                logger.info(
-                    f"End of frames at port {p} detected; ending synchronization"
-                )
-                
+                logger.info(f"End of frames at port {p} detected; ending synchronization")
+
                 self.frames_complete = True
                 self.stop_event.set()
 
@@ -188,10 +177,7 @@ def latest_current_frame(self, port):
 
     def frame_slack(self):
         """Determine how many unassigned frames are sitting in self.dataframe"""
-        slack = [
-            self.port_frame_count[port] - self.port_current_frame[port]
-            for port in self.ports
-        ]
+        slack = [self.port_frame_count[port] - self.port_current_frame[port] for port in self.ports]
         logger.debug(f"Slack in frames is {slack}")
         return min(slack)
 
@@ -205,14 +191,12 @@ def average_fps(self):
         return 1 / mean_delta_t
 
     def synch_frames_worker(self):
-
         logger.info("Waiting for all ports to begin harvesting corners...")
 
         sync_index = 0
 
         logger.info("About to start synchronizing frames...")
         while not self.stop_event.is_set():
-
             current_frame_packets = {}
 
             layer_frame_times = []
@@ -245,14 +229,10 @@ def synch_frames_worker(self):
                     # if it's closer to the earliest next frame than the latest current frame, bump it up
                     # only applying for 2 camera setup where I noticed this was an issue (frames stay out of synch)
                     current_frame_packets[port] = None
-                    logger.warning(
-                        f"Skipped frame at port {port}: delta < time-latest_current"
-                    )
+                    logger.warning(f"Skipped frame at port {port}: delta < time-latest_current")
                 else:
                     # add the data and increment the index
-                    current_frame_packets[port] = self.all_frame_packets.pop(
-                        port_index_key
-                    )
+                    current_frame_packets[port] = self.all_frame_packets.pop(port_index_key)
                     # frame_packets[port]["sync_index"] = sync_index
                     self.port_current_frame[port] += 1
                     layer_frame_times.append(frame_time)
@@ -266,9 +246,9 @@ def synch_frames_worker(self):
 
             logger.debug(f"Updating sync packet for sync_index {sync_index}")
             self.current_sync_packet = SyncPacket(sync_index, current_frame_packets)
-            
+
             self.update_dropped_frame_history()
-            
+
             sync_index += 1
 
             if self.stop_event.is_set():
@@ -278,9 +258,11 @@ def synch_frames_worker(self):
             for q in self.synched_frames_subscribers:
                 q.put(self.current_sync_packet)
                 if self.current_sync_packet is not None:
-                    logger.debug(f"Placing new synched frames packet on queue with {self.current_sync_packet.frame_packet_count} frames")
+                    logger.debug(
+                        f"Placing new synched frames packet on queue with {self.current_sync_packet.frame_packet_count} frames"  # noqa E501
+                    )
                     logger.debug(f"Placing new synched frames with index {self.current_sync_packet.sync_index}")
-                    
+
                     # provide infrequent notice of synchronizer activity
                     if self.current_sync_packet.sync_index % 100 == 0:
                         logger.info(f"Placing new synched frames with index {self.current_sync_packet.sync_index}")
@@ -288,8 +270,7 @@ def synch_frames_worker(self):
                     logger.info("signaling end of frames with `None` packet on subscriber queue.")
                     for port, q in self.frame_packet_queues.items():
                         logger.info(f"Currently {q.qsize()} frame packets unprocessed for port {port}")
-                    
+
             self.fps_mean = self.average_fps()
 
         logger.info("Frame synch worker successfully ended")
-
diff --git a/caliscope/configurator.py b/caliscope/configurator.py
index 525fd907..091642e1 100644
--- a/caliscope/configurator.py
+++ b/caliscope/configurator.py
@@ -1,36 +1,38 @@
 # %%
 
-import caliscope.logger
-
-from pathlib import Path
+from dataclasses import asdict
 from datetime import datetime
+from enum import Enum
 from os.path import exists
+from pathlib import Path
+
+import cv2
 import numpy as np
 import rtoml
-from dataclasses import asdict
-import cv2
-from enum import Enum, auto
 
+import caliscope.logger
+from caliscope.calibration.capture_volume.capture_volume import CaptureVolume
+from caliscope.calibration.capture_volume.point_estimates import PointEstimates
 from caliscope.calibration.charuco import Charuco
 from caliscope.cameras.camera import Camera
 from caliscope.cameras.camera_array import CameraArray, CameraData
-from caliscope.calibration.capture_volume.point_estimates import PointEstimates
-from caliscope.calibration.capture_volume.capture_volume import CaptureVolume
-from concurrent.futures import ThreadPoolExecutor
 
 logger = caliscope.logger.get(__name__)
 
+
 class ConfigSettings(Enum):
     """
     Control settings used to manage the processing of data
     """
+
     creation_date = "creation_date"
     camera_count = "camera_count"
     save_tracked_points_video = "save_tracked_points_video"
     fps_sync_stream_processing = "fps_sync_stream_processing"
 
-    
-#%%
+
+# %%
+
 
 class Configurator:
     """
@@ -41,9 +43,7 @@ class Configurator:
     def __init__(self, workspace_path: Path) -> None:
         self.workspace_path = workspace_path
         self.config_toml_path = Path(self.workspace_path, "config.toml")
-        self.point_estimates_toml_path = Path(
-            self.workspace_path, "point_estimates.toml"
-        )
+        self.point_estimates_toml_path = Path(self.workspace_path, "point_estimates.toml")
 
         if exists(self.config_toml_path):
             self.refresh_config_from_toml()
@@ -52,9 +52,7 @@ def __init__(self, workspace_path: Path) -> None:
             if "camera_count" not in self.dict.keys():
                 self.dict["camera_count"] = 0
         else:
-            logger.info(
-                "No existing config.toml found; creating starter file with charuco"
-            )
+            logger.info("No existing config.toml found; creating starter file with charuco")
             self.dict = rtoml.loads("")
             self.dict[ConfigSettings.creation_date.value] = datetime.now()
             self.dict[ConfigSettings.camera_count.value] = 0
@@ -74,20 +72,18 @@ def save_camera_count(self, count):
     def get_camera_count(self):
         return self.dict[ConfigSettings.camera_count.value]
 
-
     def get_save_tracked_points(self):
         if ConfigSettings.save_tracked_points_video.value not in self.dict.keys():
             return True
         else:
             return self.dict[ConfigSettings.save_tracked_points_video.value]
-    
+
     def get_fps_sync_stream_processing(self):
         if ConfigSettings.fps_sync_stream_processing.value not in self.dict.keys():
-            return 100 
+            return 100
         else:
             return self.dict[ConfigSettings.fps_sync_stream_processing.value]
-        
-        
+
     def refresh_config_from_toml(self):
         logger.info("Populating config dictionary with config.toml data")
         # with open(self.config_toml_path, "r") as f:
@@ -103,9 +99,7 @@ def update_config_toml(self):
         sorted_dict = {key: value for key, value in sorted(self.dict.items())}
         self.dict = sorted_dict
 
-        dict_wo_point_estimates = {
-            key: value for key, value in self.dict.items() if key != "point_estimates"
-        }
+        dict_wo_point_estimates = {key: value for key, value in self.dict.items() if key != "point_estimates"}
         with open(self.config_toml_path, "w") as f:
             rtoml.dump(dict_wo_point_estimates, f)
 
@@ -118,9 +112,7 @@ def save_capture_volume(self, capture_volume: CaptureVolume):
         self.dict["capture_volume"] = {}
         # self["capture_volume"]["RMSE_summary"] = self.capture_volume.rmse
         self.dict["capture_volume"]["stage"] = capture_volume.stage
-        self.dict["capture_volume"][
-            "origin_sync_index"
-        ] = capture_volume.origin_sync_index
+        self.dict["capture_volume"]["origin_sync_index"] = capture_volume.origin_sync_index
         self.update_config_toml()
 
     def get_configured_camera_data(self) -> dict[CameraData]:
@@ -130,9 +122,7 @@ def get_configured_camera_data(self) -> dict[CameraData]:
                 port = params["port"]
 
                 if (
-                    "error" in params.keys()
-                    and params["error"] is not None
-                    and params["error"] != "null"
+                    "error" in params.keys() and params["error"] is not None and params["error"] != "null"
                 ):  # intrinsics have been calculated
                     error = params["error"]
                     matrix = np.array(params["matrix"])
@@ -332,6 +322,7 @@ def save_point_estimates(self, point_estimates: PointEstimates):
 
 if __name__ == "__main__":
     import rtoml
+
     from caliscope import __app_dir__
 
     app_settings = rtoml.load(Path(__app_dir__, "settings.toml"))
diff --git a/caliscope/controller.py b/caliscope/controller.py
index 0b273ab0..49b9b606 100644
--- a/caliscope/controller.py
+++ b/caliscope/controller.py
@@ -1,39 +1,38 @@
-from PySide6.QtCore import QObject, Signal, QThread
-import numpy as np
-import cv2
-from enum import Enum, auto
+from collections import OrderedDict
 from pathlib import Path
-from PySide6.QtGui import QPixmap
 from time import sleep, time
-from caliscope.packets import Tracker
-from caliscope.trackers.tracker_enum import TrackerEnum
-from caliscope.post_processing.post_processor import PostProcessor
-from caliscope.calibration.charuco import Charuco
-from caliscope.intrinsic_stream_manager import IntrinsicStreamManager
-from caliscope.configurator import Configurator
-from caliscope.trackers.charuco_tracker import CharucoTracker
-from caliscope.calibration.stereocalibrator import StereoCalibrator
+
+import numpy as np
+from PySide6.QtCore import QObject, QThread, Signal
+
+import caliscope.logger
 from caliscope.calibration.capture_volume.capture_volume import CaptureVolume
-from caliscope.calibration.capture_volume.point_estimates import PointEstimates
-from caliscope.cameras.camera_array import CameraArray, CameraData
-from caliscope.cameras.camera_array_initializer import CameraArrayInitializer
-from caliscope.calibration.capture_volume.quality_controller import QualityController
 from caliscope.calibration.capture_volume.helper_functions.get_point_estimates import (
     get_point_estimates,
 )
+from caliscope.calibration.capture_volume.point_estimates import PointEstimates
+from caliscope.calibration.capture_volume.quality_controller import QualityController
+from caliscope.calibration.charuco import Charuco
+from caliscope.calibration.stereocalibrator import StereoCalibrator
+from caliscope.cameras.camera_array import CameraArray, CameraData
+from caliscope.cameras.camera_array_initializer import CameraArrayInitializer
+from caliscope.configurator import Configurator
+from caliscope.intrinsic_stream_manager import IntrinsicStreamManager
+from caliscope.post_processing.post_processor import PostProcessor
 from caliscope.synchronized_stream_manager import (
     SynchronizedStreamManager,
     read_video_properties,
 )
+from caliscope.trackers.charuco_tracker import CharucoTracker
+from caliscope.trackers.tracker_enum import TrackerEnum
 from caliscope.workspace_guide import WorkspaceGuide
-from collections import OrderedDict
-
-import caliscope.logger
 
 logger = caliscope.logger.get(__name__)
 
 
-FILTERED_FRACTION = 0.025  # by default, 2.5% of image points with highest reprojection error are filtered out during calibration
+FILTERED_FRACTION = (
+    0.025  # by default, 2.5% of image points with highest reprojection error are filtered out during calibration
+)
 
 
 # class CalibrationStage(Enum):
@@ -56,7 +55,7 @@ class Controller(QObject):
     enable_inputs = Signal(int, bool)  # port, enable
     post_processing_complete = Signal()
     show_synched_frames = Signal()
-    
+
     def __init__(self, workspace_dir: Path):
         super().__init__()
         self.workspace = workspace_dir
@@ -68,7 +67,6 @@ def __init__(self, workspace_dir: Path):
         logger.info("Retrieving charuco from config")
         self.charuco = self.config.get_charuco()
         self.charuco_tracker = CharucoTracker(self.charuco)
-        # self.camera_count = self.config.get_camera_count()  # reference to ensure that files are in place to meet user intent
 
         logger.info("Building workpace guide")
         self.workspace_guide = WorkspaceGuide(self.workspace, self.camera_count)
@@ -82,7 +80,7 @@ def __init__(self, workspace_dir: Path):
         self.load_workspace_thread = QThread()
         self.calibrate_camera_threads = {}
         self.autocalibrate_threads = {}
-        
+
     def load_workspace(self):
         def worker():
             logger.info("Assess whether to load cameras")
@@ -136,7 +134,7 @@ def all_extrinsics_estimated(self) -> bool:
         logger.info(f"Point estimates available: {point_estimates_good}")
         all_data_available = self.workspace_guide.all_extrinsic_mp4s_available()
         logger.info(f"All underlying data available: {all_data_available}")
-        
+
         return cameras_good and point_estimates_good and all_data_available
 
     def recordings_available(self) -> bool:
@@ -155,9 +153,7 @@ def update_charuco(self, charuco: Charuco):
             self.intrinsic_stream_manager.update_charuco(self.charuco_tracker)
 
     def load_extrinsic_stream_manager(self):
-        logger.info(
-            f"Loading manager for streams saved to {self.workspace_guide.extrinsic_dir}"
-        )
+        logger.info(f"Loading manager for streams saved to {self.workspace_guide.extrinsic_dir}")
         self.extrinsic_stream_manager = SynchronizedStreamManager(
             recording_dir=self.workspace_guide.extrinsic_dir,
             all_camera_data=self.camera_array.cameras,
@@ -203,9 +199,7 @@ def load_camera_array(self):
         self.camera_array = CameraArray(preconfigured_cameras)
 
         # double check that no new camera associated files have been placed in the intrinsic calibration folder
-        all_ports = self.workspace_guide.get_ports_in_dir(
-            self.workspace_guide.intrinsic_dir
-        )
+        all_ports = self.workspace_guide.get_ports_in_dir(self.workspace_guide.intrinsic_dir)
 
         for port in all_ports:
             if port not in self.camera_array.cameras:
@@ -262,7 +256,7 @@ def scale_intrinsic_stream(self, port, new_scale):
     def calibrate_camera(self, port):
         def worker():
             if self.intrinsic_stream_manager.calibrators[port].grid_count > 0:
-                self.enable_inputs.emit(port, False) 
+                self.enable_inputs.emit(port, False)
                 self.camera_array.cameras[port].erase_calibration_data()
                 logger.info(f"Calibrating camera at port {port}")
                 self.intrinsic_stream_manager.calibrate_camera(port)
@@ -270,9 +264,9 @@ def worker():
                 camera_data = self.camera_array.cameras[port]
                 self.config.save_camera(camera_data)
                 self.push_camera_data(port)
-                self.enable_inputs.emit(port, True) 
+                self.enable_inputs.emit(port, True)
             else:
-                logger.warn("Not enough grids available to calibrate")
+                logger.warning("Not enough grids available to calibrate")
 
         self.calibrate_camera_threads[port] = QThread()
         self.calibrate_camera_threads[port].run = worker
@@ -299,9 +293,7 @@ def rotate_camera(self, port, change):
             camera_data.rotation_count = count
 
         # note that extrinsic streams not altered.... just reload an replay
-        self.intrinsic_stream_manager.set_stream_rotation(
-            port, camera_data.rotation_count
-        )
+        self.intrinsic_stream_manager.set_stream_rotation(port, camera_data.rotation_count)
 
         self.push_camera_data(port)
         self.config.save_camera(camera_data)
@@ -321,15 +313,11 @@ def load_estimated_capture_volume(self):
 
         self.capture_volume.stage = self.config.dict["capture_volume"]["stage"]
         if "origin_sync_index" in self.config.dict["capture_volume"].keys():
-            self.capture_volume.origin_sync_index = self.config.dict["capture_volume"][
-                "origin_sync_index"
-            ]
+            self.capture_volume.origin_sync_index = self.config.dict["capture_volume"]["origin_sync_index"]
 
         # QC needed to get the corner distance accuracy within the GUI
         # Note that the corner distance accuracy calcs need validation...I'm not relying on them now...
-        self.quality_controller = QualityController(
-            self.capture_volume, charuco=self.charuco
-        )
+        self.quality_controller = QualityController(self.capture_volume, charuco=self.charuco)
 
     def calibrate_capture_volume(self):
         """
@@ -339,33 +327,27 @@ def calibrate_capture_volume(self):
         """
 
         def worker():
-            output_path = Path(
-                self.workspace_guide.extrinsic_dir, "CHARUCO", "xy_CHARUCO.csv"
-            )
+            output_path = Path(self.workspace_guide.extrinsic_dir, "CHARUCO", "xy_CHARUCO.csv")
             if output_path.exists():
                 output_path.unlink()  # make sure this doesn't exist to begin with.
 
             self.load_extrinsic_stream_manager()
 
-            # config settings that help to throttle processing rate to manage resource demands            
+            # config settings that help to throttle processing rate to manage resource demands
             include_video = self.config.get_save_tracked_points()
             fps_target = self.config.get_fps_sync_stream_processing()
-            
+
             self.extrinsic_stream_manager.process_streams(fps_target=fps_target, include_video=include_video)
-            logger.info(
-                f"Processing of extrinsic calibration begun...waiting for output to populate: {output_path}"
-            )
+            logger.info(f"Processing of extrinsic calibration begun...waiting for output to populate: {output_path}")
 
             logger.info("About to signal that synched frames should be shown")
             self.show_synched_frames.emit()
-            
+
             while not output_path.exists():
                 sleep(0.5)
                 # moderate the frequency with which logging statements get made
                 if round(time()) % 3 == 0:
-                    logger.info(
-                        f"Waiting for 2D tracked points to populate at {output_path}"
-                    )
+                    logger.info(f"Waiting for 2D tracked points to populate at {output_path}")
 
             # note that this processing will wait until it is complete
             # self.process_extrinsic_streams(fps_target=100)
@@ -375,9 +357,7 @@ def worker():
                 self.workspace, "calibration", "extrinsic", "CHARUCO", "xy_CHARUCO.csv"
             )
 
-            stereocalibrator = StereoCalibrator(
-                self.config.config_toml_path, self.extrinsic_calibration_xy
-            )
+            stereocalibrator = StereoCalibrator(self.config.config_toml_path, self.extrinsic_calibration_xy)
             stereocalibrator.stereo_calibrate_all(boards_sampled=10)
 
             # refreshing camera array from config file
@@ -385,20 +365,14 @@ def worker():
                 self.config.config_toml_path
             ).get_best_camera_array()
 
-            self.point_estimates: PointEstimates = get_point_estimates(
-                self.camera_array, self.extrinsic_calibration_xy
-            )
+            self.point_estimates: PointEstimates = get_point_estimates(self.camera_array, self.extrinsic_calibration_xy)
 
             self.capture_volume = CaptureVolume(self.camera_array, self.point_estimates)
             self.capture_volume.optimize()
 
-            self.quality_controller = QualityController(
-                self.capture_volume, self.charuco
-            )
+            self.quality_controller = QualityController(self.capture_volume, self.charuco)
 
-            logger.info(
-                f"Removing the worst fitting {FILTERED_FRACTION*100} percent of points from the model"
-            )
+            logger.info(f"Removing the worst fitting {FILTERED_FRACTION*100} percent of points from the model")
             self.quality_controller.filter_point_estimates(FILTERED_FRACTION)
             self.capture_volume.optimize()
 
@@ -407,29 +381,26 @@ def worker():
 
         self.calibrate_capture_volume_thread = QThread()
         self.calibrate_capture_volume_thread.run = worker
-        self.calibrate_capture_volume_thread.finished.connect(
-            self.capture_volume_calibrated.emit
-        )
+        self.calibrate_capture_volume_thread.finished.connect(self.capture_volume_calibrated.emit)
         self.calibrate_capture_volume_thread.start()
 
     def process_recordings(self, recording_path: Path, tracker_enum: TrackerEnum):
         """
         Initiates worker thread to begin post processing.
-        TrackerEnum passed in so that access is given to both the tracker and the name because the name is needed for file/folder naming
+        TrackerEnum passed in so that access is given to both the tracker and the name
+        The name is needed for file/folder naming
         """
 
         def worker():
             logger.info(f"Beginning to process video files at {recording_path}")
             logger.info(f"Creating post processor for {recording_path}")
-            self.post_processor = PostProcessor(
-                self.camera_array, recording_path, tracker_enum
-            )
+            self.post_processor = PostProcessor(self.camera_array, recording_path, tracker_enum)
 
-            # config settings that help to throttle processing rate to manage resource demands            
+            # config settings that help to throttle processing rate to manage resource demands
             include_video = self.config.get_save_tracked_points()
             fps_target = self.config.get_fps_sync_stream_processing()
 
-            self.post_processor.create_xy(include_video=include_video,fps_target=fps_target)
+            self.post_processor.create_xy(include_video=include_video, fps_target=fps_target)
             self.post_processor.create_xyz()
 
         self.process_recordings_thread = QThread()
@@ -439,24 +410,12 @@ def worker():
 
     def rotate_capture_volume(self, direction: str):
         transformations = {
-            "x+": np.array(
-                [[1, 0, 0, 0], [0, 0, 1, 0], [0, -1, 0, 0], [0, 0, 0, 1]], dtype=float
-            ),
-            "x-": np.array(
-                [[1, 0, 0, 0], [0, 0, -1, 0], [0, 1, 0, 0], [0, 0, 0, 1]], dtype=float
-            ),
-            "y+": np.array(
-                [[0, 0, -1, 0], [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]], dtype=float
-            ),
-            "y-": np.array(
-                [[0, 0, 1, 0], [0, 1, 0, 0], [-1, 0, 0, 0], [0, 0, 0, 1]], dtype=float
-            ),
-            "z+": np.array(
-                [[0, 1, 0, 0], [-1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], dtype=float
-            ),
-            "z-": np.array(
-                [[0, -1, 0, 0], [1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], dtype=float
-            ),
+            "x+": np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, -1, 0, 0], [0, 0, 0, 1]], dtype=float),
+            "x-": np.array([[1, 0, 0, 0], [0, 0, -1, 0], [0, 1, 0, 0], [0, 0, 0, 1]], dtype=float),
+            "y+": np.array([[0, 0, -1, 0], [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]], dtype=float),
+            "y-": np.array([[0, 0, 1, 0], [0, 1, 0, 0], [-1, 0, 0, 0], [0, 0, 0, 1]], dtype=float),
+            "z+": np.array([[0, 1, 0, 0], [-1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], dtype=float),
+            "z-": np.array([[0, -1, 0, 0], [1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], dtype=float),
         }
 
         self.capture_volume.shift_origin(transformations[direction])
@@ -483,25 +442,22 @@ def worker():
 
     def autocalibrate(self, port, grid_count, board_threshold):
         def worker():
-            self.enable_inputs.emit(port, False) 
+            self.enable_inputs.emit(port, False)
             self.camera_array.cameras[port].erase_calibration_data()
             self.config.save_camera(self.camera_array.cameras[port])
             self.push_camera_data(port)
             logger.info(f"Initiate autocalibration of grids for port {port}")
-            self.intrinsic_stream_manager.autocalibrate(
-                port, grid_count, board_threshold
-            )
+            self.intrinsic_stream_manager.autocalibrate(port, grid_count, board_threshold)
 
             while self.camera_array.cameras[port].matrix is None:
                 logger.info(f"Waiting for calibration to complete at port {port}")
                 sleep(2)
-            
+
             self.config.save_camera(self.camera_array.cameras[port])
             self.push_camera_data(port)
             self.intrinsic_stream_manager.stream_jump_to(port, 0)
-            self.enable_inputs.emit(port, True) 
+            self.enable_inputs.emit(port, True)
 
         self.autocalibrate_threads[port] = QThread()
         self.autocalibrate_threads[port].run = worker
         self.autocalibrate_threads[port].start()
-            
\ No newline at end of file
diff --git a/caliscope/export.py b/caliscope/export.py
index a7825a14..ab39e254 100644
--- a/caliscope/export.py
+++ b/caliscope/export.py
@@ -1,12 +1,15 @@
-import caliscope.logger
+import csv
 from pathlib import Path
+
 import pandas as pd
-import csv
 
+import caliscope.logger
 from caliscope.packets import Tracker
+
 logger = caliscope.logger.get(__name__)
 
-def xyz_to_wide_labelled(xyz:pd.DataFrame, tracker:Tracker)->pd.DataFrame:
+
+def xyz_to_wide_labelled(xyz: pd.DataFrame, tracker: Tracker) -> pd.DataFrame:
     """
     Will save a csv file in the same directory as the long xyz point data
     Column headings will be based on the point_id names in the Tracker
@@ -25,9 +28,7 @@ def xyz_to_wide_labelled(xyz:pd.DataFrame, tracker:Tracker)->pd.DataFrame:
 
     xyz["point_name"] = xyz["point_id"].map(tracker.get_point_name)
     # pivot the DataFrame wider
-    df_wide = xyz.pivot_table(
-        index=["sync_index"], columns="point_name", values=["x", "y", "z"]
-    )
+    df_wide = xyz.pivot_table(index=["sync_index"], columns="point_name", values=["x", "y", "z"])
     # flatten the column names
     df_wide.columns = ["{}_{}".format(y, x) for x, y in df_wide.columns]
     # reset the index
@@ -38,11 +39,12 @@ def xyz_to_wide_labelled(xyz:pd.DataFrame, tracker:Tracker)->pd.DataFrame:
     df_merged = df_merged.sort_index(axis=1, ascending=True)
     return df_merged
 
-def xyz_to_trc(xyz:pd.DataFrame, tracker:Tracker, time_history_path:Path, target_path:Path):
+
+def xyz_to_trc(xyz: pd.DataFrame, tracker: Tracker, time_history_path: Path, target_path: Path):
     """
     Will save a .trc file in the same folder as the long xyz data
     relies on xyz_to_wide_csv for input data
-    """  
+    """
     # create xyz_labelled file to provide input for trc creation
     xyz_labelled = xyz_to_wide_labelled(xyz, tracker)
 
@@ -56,7 +58,7 @@ def xyz_to_trc(xyz:pd.DataFrame, tracker:Tracker, time_history_path:Path, target
 
     # Shift times so that it starts at zero
     min_time = sync_time.min()
-    sync_time = round(sync_time - min_time,3)
+    sync_time = round(sync_time - min_time, 3)
     xyz_labelled.insert(1, "mean_frame_time", sync_time)
     # %%
 
@@ -64,20 +66,16 @@ def xyz_to_trc(xyz:pd.DataFrame, tracker:Tracker, time_history_path:Path, target
     xyz_labelled.sort_values(by="mean_frame_time", inplace=True)
     xyz_labelled["time_diff"] = xyz_labelled["mean_frame_time"].diff()
 
-        
-
     # Calculate frame rate for each pair of frames (avoid division by zero)
-    xyz_labelled["frame_rate"] = xyz_labelled["time_diff"].apply(
-        lambda x: 1 / x if x != 0 else 0
-    )
+    xyz_labelled["frame_rate"] = xyz_labelled["time_diff"].apply(lambda x: 1 / x if x != 0 else 0)
 
     # Calculate mean frame rate (drop the first value which is NaN due to the diff operation)
     mean_frame_rate = xyz_labelled["frame_rate"].dropna().mean()
-    
+
     # Rename 'sync_index' to 'Frame' and 'mean_frame_time' to 'Time'
-    xyz_labelled = xyz_labelled.reset_index() # need sync_index to be just a regular column
-    xyz_labelled.rename(columns={'sync_index': 'Frame', 'mean_frame_time': 'Time'}, inplace=True)
-    xyz_labelled.drop(columns=["time_diff", "frame_rate"], inplace=True) # no longer needed
+    xyz_labelled = xyz_labelled.reset_index()  # need sync_index to be just a regular column
+    xyz_labelled.rename(columns={"sync_index": "Frame", "mean_frame_time": "Time"}, inplace=True)
+    xyz_labelled.drop(columns=["time_diff", "frame_rate"], inplace=True)  # no longer needed
 
     # Make sure all following fields are in alphabetical order
     # First, get the columns to be sorted, i.e., all columns excluding 'Frame' and 'Time'
@@ -87,89 +85,89 @@ def xyz_to_trc(xyz:pd.DataFrame, tracker:Tracker, time_history_path:Path, target
     # Now, sort these columns
     cols_to_sort.sort()
     # Now, create the final column order and rearrange the DataFrame
-    final_col_order = ['Frame', 'Time'] + cols_to_sort
+    final_col_order = ["Frame", "Time"] + cols_to_sort
     xyz_labelled = xyz_labelled[final_col_order]
 
     # trying a fix...
     xyz_labelled["Frame"] = xyz_labelled["Frame"].astype(int)
-    
+
     # Get column names from dataframe
     columns = xyz_labelled.columns
 
     # Remove '_x', '_y', and '_z' suffixes and get unique names
-    tracked_points = list(
-        set([col.rsplit("_", 1)[0] for col in columns if col.endswith(("_x", "_y", "_z"))])
-    )
+    tracked_points = list(set([col.rsplit("_", 1)[0] for col in columns if col.endswith(("_x", "_y", "_z"))]))
     tracked_points.sort()
 
-
     num_markers = len(tracked_points)
     data_rate = int(mean_frame_rate)
     units = "m"
-    original_data_rate = int(mean_frame_rate)
+    # original_data_rate = int(mean_frame_rate)
     orig_data_start_frame = 0
-    num_frames = len(xyz_labelled)-1
+    num_frames = len(xyz_labelled) - 1
 
-    trc_path = Path(target_path.parent,f"{target_path.stem}.trc")
+    trc_path = Path(target_path.parent, f"{target_path.stem}.trc")
     trc_filename = str(trc_path)
 
     # this will create the formatted .trc file
-    with open(trc_path, 'wt', newline='', encoding='utf-8') as out_file:
-        tsv_writer = csv.writer(out_file, delimiter='\t')
-        tsv_writer.writerow(["PathFileType",
-                            "4", 
-                            "(X/Y/Z)",	
-                            trc_filename])
-        tsv_writer.writerow(["DataRate",
-                            "CameraRate",
-                            "NumFrames",
-                            "NumMarkers", 
-                            "Units",
-                            "OrigDataRate",
-                            "OrigDataStartFrame",
-                            "OrigNumFrames"])
-        tsv_writer.writerow([data_rate, 
-                            int(mean_frame_rate),
-                            num_frames, 
-                            num_markers, 
-                            units, 
-                            int(mean_frame_rate), 
-                            orig_data_start_frame, 
-                            num_frames])
+    with open(trc_path, "wt", newline="", encoding="utf-8") as out_file:
+        tsv_writer = csv.writer(out_file, delimiter="\t")
+        tsv_writer.writerow(["PathFileType", "4", "(X/Y/Z)", trc_filename])
+        tsv_writer.writerow(
+            [
+                "DataRate",
+                "CameraRate",
+                "NumFrames",
+                "NumMarkers",
+                "Units",
+                "OrigDataRate",
+                "OrigDataStartFrame",
+                "OrigNumFrames",
+            ]
+        )
+        tsv_writer.writerow(
+            [
+                data_rate,
+                int(mean_frame_rate),
+                num_frames,
+                num_markers,
+                units,
+                int(mean_frame_rate),
+                orig_data_start_frame,
+                num_frames,
+            ]
+        )
 
         # create names of trajectories, skipping two columns (top of table)
-        header_names = ['Frame#', 'Time']
+        header_names = ["Frame#", "Time"]
         for trajectory in tracked_points:
             header_names.append(trajectory)
             header_names.append("")
-            header_names.append("")    
+            header_names.append("")
 
         tsv_writer.writerow(header_names)
 
         # create labels for x,y,z axes (below landmark names in header)
-        header_names = ["",""]
-        for i in range(1,len(tracked_points)+1):
-            header_names.append("X"+str(i))
-            header_names.append("Y"+str(i))
-            header_names.append("Z"+str(i))
+        header_names = ["", ""]
+        for i in range(1, len(tracked_points) + 1):
+            header_names.append("X" + str(i))
+            header_names.append("Y" + str(i))
+            header_names.append("Z" + str(i))
 
         tsv_writer.writerow(header_names)
 
         # the .trc fileformat expects a blank fourth line
         tsv_writer.writerow("")
 
-
         # this is here primarily for testing purposes right now..
         # filLs None with zeros.
         # df_xyz_labelled.fillna(0,inplace=True)
 
-
         # and finally actually write the trajectories
         for row in range(0, len(xyz_labelled)):
             row_data = xyz_labelled.iloc[row].tolist()
-    
+
             # Convert the 'Frame' column value to int to satisfy trc format requirements
-            frame_index = xyz_labelled.columns.get_loc('Frame')
+            frame_index = xyz_labelled.columns.get_loc("Frame")
             row_data[frame_index] = int(row_data[frame_index])
 
-            tsv_writer.writerow(row_data)
\ No newline at end of file
+            tsv_writer.writerow(row_data)
diff --git a/caliscope/gui/calibrate_capture_volume_widget.py b/caliscope/gui/calibrate_capture_volume_widget.py
deleted file mode 100644
index 8845e955..00000000
--- a/caliscope/gui/calibrate_capture_volume_widget.py
+++ /dev/null
@@ -1,102 +0,0 @@
-import caliscope.logger
-
-
-import os
-import sys
-import shutil
-import time
-from pathlib import Path
-from threading import Thread
-from PySide6.QtCore import Qt, Signal
-from PySide6.QtGui import QIcon, QAction
-from PySide6.QtWidgets import (
-    QWidget,
-    QApplication,
-    QVBoxLayout,
-    QHBoxLayout,
-    QDockWidget,
-    QFileDialog,
-    QStackedWidget,
-)
-
-from caliscope.session.session import LiveSession, SessionMode
-from caliscope.gui.charuco_widget import CharucoWidget
-from caliscope.gui.live_camera_config.intrinsic_calibration_widget import IntrinsicCalibrationWidget
-from caliscope import __root__, __app_dir__
-from caliscope.trackers.charuco_tracker import CharucoTracker
-# from caliscope.gui.qt_logger import QtLogger
-from caliscope.gui.extrinsic_calibration_widget import (
-    ExtrinsicCalibrationWidget,
-    MIN_THRESHOLD_FOR_EARLY_CALIBRATE,
-)
-from caliscope.gui.vizualize.calibration.capture_volume_widget import CaptureVolumeWidget
-from caliscope.configurator import Configurator
-
-logger = caliscope.logger.get(__name__)
-
-class CalibrateCaptureVolumeWidget(QStackedWidget):
-    """
-    A combination of the Extrinsic Calibration Widget and the Capture Volume Widget
-    Allows the user to move back and forth between the two functions.
-    """
-    cameras_connected = Signal()
-
-    def __init__(self, session:LiveSession):
-        super().__init__()
-        self.CAMS_IN_PROCESS = False
-
-        self.session = session
-
-        if self.session.is_capture_volume_eligible():
-            logger.info("able to load Capture Volume, proceeeding with load of capture volume widget")
-            self.activate_capture_volume_widget()
-        else:
-            logger.info("Unable to load capture volume from config; load extrinsic calibration widget")
-            self.activate_extrinsic_calibration_widget()
-
-    ###################### Stereocalibration  ######################################
-    def activate_extrinsic_calibration_widget(self):
-        logger.info(f"Setting session mode to {SessionMode.ExtrinsicCalibration} from within subwidget")
-        self.session.set_mode(SessionMode.ExtrinsicCalibration)
-
-        if hasattr(self, "extrinsic_calibration_widget"):
-            logger.info("Activate extrinsic calibration widget")
-            self.extrinsic_calibration_widget.deleteLater()
-            self.extrinsic_calibration_widget = None
-            # self.setCurrentWidget(self.extrinsic_calibration_widget)
-
-        logger.info("Create new extrinsic calibration widget")
-        self.extrinsic_calibration_widget = ExtrinsicCalibrationWidget(self.session)
-        self.addWidget(self.extrinsic_calibration_widget)
-        self.setCurrentWidget(self.extrinsic_calibration_widget)
-        # self.extrinsic_calibration_widget.calibration_complete.connect(self.activate_capture_volume_widget)
-        self.extrinsic_calibration_widget.update_btn_eligibility()
-        
-        # self.session.unpause_synchronizer()
-        
-
-    def activate_capture_volume_widget(self):
-
-        logger.info(f"Setting session mode to {SessionMode.CaptureVolumeOrigin} from within subwidget")
-        self.session.set_mode(SessionMode.CaptureVolumeOrigin)
-
-        if hasattr(self, "capture_volume_widget"):
-            logger.info("Set current index to capture volume widget")
-            self.capture_volume_widget.deleteLater()
-            self.capture_volume_widget = None            
-
-        logger.info("Creating Capture Volume widget")
-        self.capture_volume_widget = CaptureVolumeWidget(self.session)
-        logger.info("Adding capture volume widget to main Wizard")
-        self.addWidget(self.capture_volume_widget)
-        self.setCurrentWidget(self.capture_volume_widget)
-
-        self.capture_volume_widget.recalibrate_btn.clicked.connect(
-            self.activate_extrinsic_calibration_widget
-        )
-        
-        # this will be managed elsewhere. StreamTools may or may not 
-        # be loaded ...
-        # self.session.pause_synchronizer()
-            
-
diff --git a/caliscope/gui/camera_management/camera_display_widget.py b/caliscope/gui/camera_management/camera_display_widget.py
index 9ccb5d39..a0b20b96 100644
--- a/caliscope/gui/camera_management/camera_display_widget.py
+++ b/caliscope/gui/camera_management/camera_display_widget.py
@@ -1,16 +1,20 @@
 import sys
-from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QTreeWidget, QTreeWidgetItem
-from caliscope.controller import Controller
-import caliscope.logger
 from collections import OrderedDict
 
+from PySide6.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
+
+import caliscope.logger
+from caliscope.controller import Controller
+
 logger = caliscope.logger.get(__name__)
 
+
 class CameraDataDisplayWidget(QWidget):
     """
     This receives a dictionary that displays the characteristics of a given camera
     """
-    def __init__(self, port:int, controller:Controller):
+
+    def __init__(self, port: int, controller: Controller):
         super().__init__()
         self.port = port
         self.controller = controller
@@ -23,17 +27,14 @@ def __init__(self, port:int, controller:Controller):
         self.controller.push_camera_data(self.port)
 
     def place_widgets(self):
-        
         layout = QVBoxLayout()
         self.setLayout(layout)
         layout.addWidget(self.tree)
         self.tree.setHeaderLabels(["Parameter", "Value"])
 
-
     def connect_widgets(self):
         self.controller.new_camera_data.connect(self.update_tree)
-        
-    
+
     def update_tree(self, port, camera_display_dict):
         # logger.info(f"Updating display tree for port {port} with camera data {camera_display_dict}")
         # port, camera_display_dict = port_camera_display_dict
@@ -44,7 +45,7 @@ def update_tree(self, port, camera_display_dict):
             self.add_items(None, self.tree, camera_display_dict)
             # Expand all items
             self.expand_all_items(self.tree)
-        
+
     def add_items(self, parent, tree, data_dict):
         if parent is None:
             parent = tree
@@ -78,36 +79,48 @@ def adjust_column_widths(self):
         self.tree.setColumnWidth(1, int(total_width * 0.3))  # 30% for value column
 
 
-if __name__ == '__main__':
-    from caliscope import __root__
+if __name__ == "__main__":
     from pathlib import Path
-    
-    app = QApplication(sys.argv)
 
+    from caliscope import __root__
+
+    app = QApplication(sys.argv)
 
-    camera_data = OrderedDict([
-        ("size", (1920, 1080)),
-        ("RMSE", 0.2),
-        ("rotation_count", 3),
-        ("intrinsic_parameters", OrderedDict([
-            ("focal_length_x", 1000),
-            ("focal_length_y", 1000),
-            ("optical_center_x", 500),
-            ("optical_center_y", 300)
-        ])),
-        ("distortion_coefficients", OrderedDict([
-            ("radial_k1", .01),
-            ("radial_k2", .02),
-            ("radial_k3", .03),
-            ("tangential_p1", .05),
-            ("tangential_p2", .09)
-        ]))
-    ])
+    camera_data = OrderedDict(
+        [
+            ("size", (1920, 1080)),
+            ("RMSE", 0.2),
+            ("rotation_count", 3),
+            (
+                "intrinsic_parameters",
+                OrderedDict(
+                    [
+                        ("focal_length_x", 1000),
+                        ("focal_length_y", 1000),
+                        ("optical_center_x", 500),
+                        ("optical_center_y", 300),
+                    ]
+                ),
+            ),
+            (
+                "distortion_coefficients",
+                OrderedDict(
+                    [
+                        ("radial_k1", 0.01),
+                        ("radial_k2", 0.02),
+                        ("radial_k3", 0.03),
+                        ("tangential_p1", 0.05),
+                        ("tangential_p2", 0.09),
+                    ]
+                ),
+            ),
+        ]
+    )
 
     test_path = Path(__root__, "tests", "sessions", "prerecorded_calibration")
     controller = Controller(test_path)
     controller.config.dict["camera_count"] = 1
-    ex = CameraDataDisplayWidget(port=0,controller=controller)
-    controller.new_camera_data.emit(0,camera_data)
+    ex = CameraDataDisplayWidget(port=0, controller=controller)
+    controller.new_camera_data.emit(0, camera_data)
     ex.show()
     sys.exit(app.exec())
diff --git a/caliscope/gui/camera_management/multiplayback_widget.py b/caliscope/gui/camera_management/multiplayback_widget.py
index 12c9711c..d3c79633 100644
--- a/caliscope/gui/camera_management/multiplayback_widget.py
+++ b/caliscope/gui/camera_management/multiplayback_widget.py
@@ -1,16 +1,18 @@
 import sys
+from pathlib import Path
+
 from PySide6.QtWidgets import (
     QApplication,
-    QVBoxLayout,
     QTabWidget,
+    QVBoxLayout,
     QWidget,
 )
-from pathlib import Path
+
+import caliscope.logger
+from caliscope.controller import Controller
 from caliscope.gui.camera_management.playback_widget import (
     IntrinsicCalibrationWidget,
 )
-from caliscope.controller import Controller
-import caliscope.logger
 
 logger = caliscope.logger.get(__name__)
 
@@ -34,9 +36,7 @@ def loadTabs(self):
         logger.info("Beginning to load individual tabs")
         for camera in self.controller.camera_array.cameras.values():
             logger.info(f"About to create calibration widget for camera {camera.port}")
-            tab = IntrinsicCalibrationWidget(
-                controller=self.controller, port=camera.port
-            )
+            tab = IntrinsicCalibrationWidget(controller=self.controller, port=camera.port)
             logger.info(f"Calibration widget for camera {camera.port} successfully created")
             self.tabWidget.addTab(tab, f"Cam {camera.port}")
 
diff --git a/caliscope/gui/camera_management/playback_widget.py b/caliscope/gui/camera_management/playback_widget.py
index 336ffeba..7796c0ca 100644
--- a/caliscope/gui/camera_management/playback_widget.py
+++ b/caliscope/gui/camera_management/playback_widget.py
@@ -1,29 +1,30 @@
 import sys
-from PySide6.QtWidgets import QStyle
-from PySide6.QtGui import QIcon, QPixmap, QPainter
 from pathlib import Path
+
+from PySide6.QtCore import Qt, Signal, Slot
+from PySide6.QtGui import QIcon, QPainter, QPixmap
+from PySide6.QtSvg import QSvgRenderer
 from PySide6.QtWidgets import (
     QApplication,
-    QSpinBox,
-    QDoubleSpinBox,
-    QMainWindow,
     QCheckBox,
-    QWidget,
+    QDoubleSpinBox,
+    QHBoxLayout,
+    QLabel,
     QPushButton,
     QSlider,
-    QLabel,
-    QHBoxLayout,
+    QSpinBox,
+    QStyle,
     QVBoxLayout,
+    QWidget,
 )
-from PySide6.QtCore import Qt, Slot, Signal, QSize
+
+import caliscope.logger
+from caliscope import __root__
+from caliscope.controller import Controller
 from caliscope.gui.camera_management.camera_display_widget import (
     CameraDataDisplayWidget,
 )
-from PySide6.QtSvg import QSvgRenderer
-from caliscope.controller import Controller
-from caliscope import __root__
 
-import caliscope.logger
 logger = caliscope.logger.get(__name__)
 
 
@@ -72,10 +73,12 @@ def checkForArrowKey(self, value):
         if self.isUsingArrowKeys():
             self.arrowKeyPressed.emit(value)  # Emit the custom signal
 
+
 # icons from https://iconoir.com
 CAM_ROTATE_RIGHT_PATH = Path(__root__, "caliscope", "gui", "icons", "rotate-camera-right.svg")
 CAM_ROTATE_LEFT_PATH = Path(__root__, "caliscope", "gui", "icons", "rotate-camera-left.svg")
 
+
 class IntrinsicCalibrationWidget(QWidget):
     def __init__(self, controller: Controller, port: int, parent=None):
         super().__init__(parent)
@@ -114,8 +117,8 @@ def __init__(self, controller: Controller, port: int, parent=None):
         self.board_threshold_spin = QDoubleSpinBox(self)
         self.board_threshold_spin.setMaximumWidth(50)
         self.board_threshold_spin.setRange(0, 1)
-        self.board_threshold_spin.setValue(.5)
-        self.board_threshold_spin.setSingleStep(.1)
+        self.board_threshold_spin.setValue(0.5)
+        self.board_threshold_spin.setSingleStep(0.1)
 
         # Create the spinbox
         self.scaling_spin = QSpinBox(self)
@@ -133,9 +136,7 @@ def place_widgets(self):
         self.setLayout(self.layout)
         self.layout.addWidget(self.camera_data_display)
         self.right_panel = QVBoxLayout()
-        self.right_panel.addWidget(
-            self.frame_image, alignment=Qt.AlignmentFlag.AlignCenter
-        )
+        self.right_panel.addWidget(self.frame_image, alignment=Qt.AlignmentFlag.AlignCenter)
 
         self.rotate_span = QHBoxLayout()
         self.rotate_span.addWidget(self.cw_rotation_btn)
@@ -149,13 +150,13 @@ def place_widgets(self):
         self.auto_control_span.addWidget(self.board_threshold_spin, alignment=Qt.AlignmentFlag.AlignLeft)
         self.auto_control_span.addWidget(self.autocalibrate_btn)
         self.right_panel.addLayout(self.auto_control_span)
-        
+
         self.play_span = QHBoxLayout()
         self.play_span.addWidget(self.play_button)
         self.play_button.setMaximumWidth(35)
         self.play_span.addWidget(self.slider)
         self.right_panel.addLayout(self.play_span)
-        
+
         self.manual_control_span = QHBoxLayout()
         self.manual_control_span.addWidget(self.add_grid_btn)
         self.manual_control_span.addWidget(self.calibrate_btn)
@@ -170,7 +171,6 @@ def place_widgets(self):
         self.right_panel.addLayout(self.distortion_control_span)
         self.layout.addLayout(self.right_panel)
 
-
     def connect_widgets(self):
         self.play_button.clicked.connect(self.play_video)
         self.slider.sliderMoved.connect(self.slider_moved)
@@ -181,11 +181,13 @@ def connect_widgets(self):
         self.toggle_distortion.stateChanged.connect(self.toggle_distortion_changed)
         self.ccw_rotation_btn.clicked.connect(self.rotate_ccw)
         self.cw_rotation_btn.clicked.connect(self.rotate_cw)
-        self.autocalibrate_btn.clicked.connect(self.autocalibrate) 
-       
+        self.autocalibrate_btn.clicked.connect(self.autocalibrate)
+
         self.scaling_spin.valueChanged.connect(self.on_scale_change)
         self.controller.intrinsic_stream_manager.frame_emitters[self.port].ImageBroadcast.connect(self.update_image)
-        self.controller.intrinsic_stream_manager.frame_emitters[self.port].FrameIndexBroadcast.connect(self.update_index)
+        self.controller.intrinsic_stream_manager.frame_emitters[self.port].FrameIndexBroadcast.connect(
+            self.update_index
+        )
         self.controller.enable_inputs.connect(self.update_enable_all_inputs)
 
         # initialize stream to push first frame to widget then hold
@@ -196,7 +198,6 @@ def connect_widgets(self):
         self.controller.pause_intrinsic_stream(self.port)
         self.controller.stream_jump_to(self.port, 0)
 
-
     def play_video(self):
         # if self.play_started:
         if self.is_playing:
@@ -252,13 +253,12 @@ def on_scale_change(self, value):
         """
         Way too much starting to happen here, but there we are...
         """
-        new_scale = value/100
+        new_scale = value / 100
         logger.info(f"Changing frame_emitter scale factor to {new_scale}")
-        self.controller.scale_intrinsic_stream(self.port, new_scale) 
+        self.controller.scale_intrinsic_stream(self.port, new_scale)
         self.controller.stream_jump_to(self.port, self.index)
 
     def calibrate(self):
-        
         self.controller.calibrate_camera(self.port)
 
     def clear_calibration_data(self):
@@ -288,8 +288,7 @@ def rotate_ccw(self):
         self.controller.rotate_camera(self.port, -1)
         self.controller.stream_jump_to(self.port, self.index)
 
-
-    def update_enable_all_inputs(self, port, enable:bool):
+    def update_enable_all_inputs(self, port, enable: bool):
         # Control widget accessibilty from controller signal to all ports
         if port == self.port:
             self.play_button.setEnabled(enable)
@@ -305,24 +304,22 @@ def update_enable_all_inputs(self, port, enable:bool):
             self.target_grid_count_spin.setEnabled(enable)
             self.board_threshold_spin.setEnabled(enable)
             self.scaling_spin.setEnabled(enable)
-        
+
     def autocalibrate(self):
         grid_count = self.target_grid_count_spin.value()
         board_threshold = self.board_threshold_spin.value()
         self.update_enable_all_inputs(self.port, False)
-        self.controller.autocalibrate(self.port,grid_count, board_threshold)
-        
+        self.controller.autocalibrate(self.port, grid_count, board_threshold)
+
+
 if __name__ == "__main__":
     app = QApplication(sys.argv)
     from caliscope import __root__
-    from caliscope.helper import copy_contents
-    from caliscope.trackers.charuco_tracker import CharucoTracker
     from caliscope.calibration.charuco import Charuco
+    from caliscope.trackers.charuco_tracker import CharucoTracker
 
     # Define the input file path here.
-    original_workspace_dir = Path(
-        __root__, "tests", "sessions", "prerecorded_calibration"
-    )
+    original_workspace_dir = Path(__root__, "tests", "sessions", "prerecorded_calibration")
     # workspace_dir = Path(
     #     __root__, "tests", "sessions_copy_delete", "prerecorded_calibration"
     # )
@@ -330,9 +327,7 @@ def autocalibrate(self):
     # copy_contents(original_workspace_dir, workspace_dir)
     workspace_dir = Path(r"C:\Users\Mac Prible\OneDrive\caliscope\prerecorded_workflow")
     controller = Controller(workspace_dir)
-    charuco = Charuco(
-        4, 5, 11, 8.5, aruco_scale=0.75, square_size_overide_cm=5.25, inverted=True
-    )
+    charuco = Charuco(4, 5, 11, 8.5, aruco_scale=0.75, square_size_overide_cm=5.25, inverted=True)
     charuco_tracker = CharucoTracker(charuco)
     controller.charuco_tracker = charuco_tracker
 
@@ -342,4 +337,4 @@ def autocalibrate(self):
     window.resize(800, 600)
     logger.info("About to show window")
     window.show()
-    sys.exit(app.exec())
\ No newline at end of file
+    sys.exit(app.exec())
diff --git a/caliscope/gui/charuco_widget.py b/caliscope/gui/charuco_widget.py
index 9b25ca3a..ae06b1eb 100644
--- a/caliscope/gui/charuco_widget.py
+++ b/caliscope/gui/charuco_widget.py
@@ -17,17 +17,19 @@
     QWidget,
 )
 
+import caliscope.logger
 from caliscope.calibration.charuco import Charuco
 from caliscope.controller import Controller
-import caliscope.logger
 
 logger = caliscope.logger.get(__name__)
+
+
 class CharucoWidget(QWidget):
-    def __init__(self, controller:Controller):
+    def __init__(self, controller: Controller):
         super().__init__()
 
         logger.info("Charuco Wizard initializing")
-        self.controller = controller 
+        self.controller = controller
         self.params = self.controller.get_charuco_params()
 
         # add group to do initial configuration of the charuco board
@@ -55,14 +57,13 @@ def __init__(self, controller:Controller):
         self.layout().addWidget(self.charuco_config)
         self.layout().setAlignment(self.charuco_config, Qt.AlignmentFlag.AlignHCenter)
         self.layout().addWidget(QLabel("<i>Top left corner is point (0,0,0) when setting capture volume origin</i>"))
-        self.layout().addWidget(self.charuco_display,2)
+        self.layout().addWidget(self.charuco_display, 2)
         self.layout().addSpacing(10)
         self.layout().addLayout(self.save_png_hbox)
         self.layout().addSpacing(10)
         self.layout().addLayout(self.true_up_hbox)
         self.layout().addWidget(QLabel("<i>Printed square size will set the scale of the capture volume</i>"))
 
-
     def build_save_png_group(self):
         # basic png save button
         self.png_btn = QPushButton("Save &png")
@@ -118,13 +119,9 @@ def build_true_up_group(self):
         self.printed_edge_length.setValue(overide)
 
         def update_charuco():
-            self.charuco.square_size_overide_cm = round(
-                self.printed_edge_length.value(), 2
-            )
+            self.charuco.square_size_overide_cm = round(self.printed_edge_length.value(), 2)
 
-            logger.info(
-                f"Updated Square Size Overide to {self.printed_edge_length.value}"
-            )
+            logger.info(f"Updated Square Size Overide to {self.printed_edge_length.value}")
             self.controller.charuco = self.charuco
             self.controller.config.save_charuco(self.charuco)
 
@@ -177,7 +174,7 @@ def build_charuco(self):
 
 
 class CharucoConfigGroup(QWidget):
-    def __init__(self, controller:Controller):
+    def __init__(self, controller: Controller):
         super().__init__()
         self.controller = controller
         self.params = self.controller.config.dict["charuco"]
@@ -242,18 +239,14 @@ def __init__(self, controller:Controller):
         ############################# INVERT ####################################
         self.config_options.addWidget(self.invert_checkbox)
 
-if __name__ == "__main__":
-
-
 
+if __name__ == "__main__":
     app = QApplication(sys.argv)
     from caliscope import __root__
     from caliscope.calibration.charuco import Charuco
 
     # Define the input file path here.
-    original_workspace_dir = Path(
-        __root__, "tests", "sessions", "prerecorded_calibration"
-    )
+    original_workspace_dir = Path(__root__, "tests", "sessions", "prerecorded_calibration")
     # workspace_dir = Path(
     #     __root__, "tests", "sessions_copy_delete", "prerecorded_calibration"
     # )
@@ -268,4 +261,4 @@ def __init__(self, controller:Controller):
     window.resize(800, 600)
     logger.info("About to show window")
     window.show()
-    sys.exit(app.exec())
\ No newline at end of file
+    sys.exit(app.exec())
diff --git a/caliscope/gui/extrinsic_calibration_widget.py b/caliscope/gui/extrinsic_calibration_widget.py
deleted file mode 100644
index 255ace80..00000000
--- a/caliscope/gui/extrinsic_calibration_widget.py
+++ /dev/null
@@ -1,301 +0,0 @@
-
-import caliscope.logger
-logger = caliscope.logger.get(__name__)
-
-import sys
-from pathlib import Path
-from threading import Thread, Event
-from time import sleep, perf_counter
-from enum import Enum
-
-import cv2
-from PySide6.QtCore import Qt, Signal, QThread
-from PySide6.QtGui import QImage, QPixmap, QIcon
-from PySide6.QtWidgets import (
-    QApplication,
-    QSizePolicy,
-    QWidget,
-    QSpinBox,
-    QScrollArea,
-    QComboBox,
-    QCheckBox,
-    QDialog,
-    QGroupBox,
-    QDoubleSpinBox,
-    QHBoxLayout,
-    QLabel,
-    QPushButton,
-    QSlider,
-    QVBoxLayout,
-)
-
-# Append main repo to top of path to allow import of backend
-from caliscope.session.session import LiveSession
-from caliscope.gui.frame_builders.paired_frame_builder import PairedFrameBuilder
-from caliscope.cameras.synchronizer import Synchronizer
-from caliscope import __root__
-from caliscope.gui.navigation_bars import NavigationBarNext
-
-# the boards needed before a pair could be used to bridge pairs without common corners
-MIN_THRESHOLD_FOR_EARLY_CALIBRATE = 5
-
-
-class PossibleActions(Enum):
-    CollectData = "Collect Data"
-    Terminate = "Terminate"
-    Calibrate = "Calibrate"
-
-class ExtrinsicCalibrationWidget(QWidget):
-    calibration_complete = Signal()
-    calibration_initiated = Signal()
-    terminate = Signal()
-     
-    def __init__(self,session:LiveSession):
-
-        super(ExtrinsicCalibrationWidget, self).__init__()
-        self.session = session
-        self.synchronizer:Synchronizer = self.session.synchronizer
-
-        logger.info(f"about to check if synchronizer has a sync packet")
-        while not hasattr(self.session.synchronizer, "current_sync_packet"):
-            logger.info("waiting for synchronizer to create first sync packet")
-            sleep(.5)
-
-        self.paired_frame_builder = PairedFrameBuilder(self.synchronizer, board_count_target=30)
-        self.paired_frame_emitter = PairedFrameEmitter(self.paired_frame_builder)
-        self.paired_frame_emitter.start()
-
-        self.frame_rate_spin = QSpinBox()
-        self.frame_rate_spin.setValue(self.synchronizer.fps_target)
-        self.board_count_spin = QSpinBox()
-        self.board_count_spin.setValue(self.paired_frame_builder.board_count_target)
-        
-        self.stereo_frame_display = QLabel()
-        # self.navigation_bar = NavigationBarNext() 
-        self.possible_action = PossibleActions.CollectData
-        self.calibrate_collect_btn = QPushButton(self.possible_action.value)
-        
-        self.place_widgets()
-        self.connect_widgets()        
-
-        self.update_btn_eligibility()
-    
-    def shutdown_threads(self):
-        """
-        There may be some lingering threads running when the extrinsic calibrator loses focus
-        This may be causing python to overload and pyqt to segfault during the calibration process
-        if I've moved from the extrinsic calibration widget to a different one...
-        """
-        logger.info("Unsubscribe paired frame builder from sync notice")
-        self.paired_frame_builder.unsubscribe_from_synchronizer()
-        logger.info("signal paired frame emitter to stop collecting frames")
-        self.paired_frame_emitter.keep_collecting.clear()
-
-    def update_btn_eligibility(self):
-        if self.session.is_extrinsic_calibration_eligible():
-            self.calibrate_collect_btn.setEnabled(True)
-        else:
-            self.calibrate_collect_btn.setEnabled(False)
-    
-
-    def place_widgets(self):
-        self.setLayout(QVBoxLayout())
-        
-        self.settings_group = QGroupBox("Settings")
-        self.settings_group.setLayout(QHBoxLayout())
-        self.settings_group.layout().addWidget(QLabel("Frame Rate:"))
-        self.settings_group.layout().addWidget(self.frame_rate_spin)       
-        self.settings_group.layout().addWidget(QLabel("Target Board Count:"))
-        self.settings_group.layout().addWidget(self.board_count_spin)       
-
-        self.layout().addWidget(self.settings_group)
-        # self.layout().addWidget(self.calibrate_collect_btn)
-
-        # scroll bar appears to not be working....
-        self.scroll_area = QScrollArea()
-        self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
-        # self.scroll_area.setLayout(QVBoxLayout())
-        self.layout().addWidget(self.scroll_area)
-
-        self.scroll_area.setWidget(self.stereo_frame_display)
-        self.scroll_area.setAlignment(Qt.AlignmentFlag.AlignHCenter)
-       
-        self.layout().addWidget(self.calibrate_collect_btn)
-
-
-
-    def connect_widgets(self):
-        
-        self.calibrate_collect_btn.clicked.connect(self.on_calibrate_collect_click)
-        self.paired_frame_emitter.ImageBroadcast.connect(self.ImageUpdateSlot)
-        self.paired_frame_emitter.possible_to_initialize_array.connect(self.enable_calibration)
-        self.frame_rate_spin.valueChanged.connect(self.synchronizer.set_stream_fps)
-        self.board_count_spin.valueChanged.connect(self.update_board_count_target)
-        self.paired_frame_emitter.calibration_data_collected.connect(self.initiate_calibration)
-    
-    def update_board_count_target(self, target):
-        self.paired_frame_builder.board_count_target = target
-        
-    def on_calibrate_collect_click(self):
-        if self.possible_action == PossibleActions.CollectData:
-            logger.info("Begin collecting calibration data")
-            # by default, data saved to session folder
-            self.paired_frame_builder.store_points.set()
-            extrinsic_calibration_path = Path(self.session.path, "calibration", "extrinsic")
-            self.session.start_recording(extrinsic_calibration_path,store_point_history=True)
-            self.possible_action = PossibleActions.Terminate
-            self.calibrate_collect_btn.setText(self.possible_action.value)
-            self.calibrate_collect_btn.setEnabled(True)
-            self.navigation_bar.back_btn.setEnabled(False)
-
-        elif self.possible_action == PossibleActions.Terminate:
-            logger.info("Terminating current data collection")
-            self.terminate.emit()
-            self.possible_action = PossibleActions.CollectData
-            self.calibrate_collect_btn.setText(self.possible_action.value)
-
-        elif self.possible_action == PossibleActions.Calibrate:
-            logger.info("Prematurely end data collection to initiate calibration")
-            self.paired_frame_builder.store_points.clear()
-            self.initiate_calibration()
-            
-
-
-    def enable_calibration(self):
-        self.possible_action = PossibleActions.Calibrate
-        self.calibrate_collect_btn.setText(self.possible_action.value)
-        self.calibrate_collect_btn.setEnabled(True)
-        
-        
-    def ImageUpdateSlot(self, q_image):
-        self.stereo_frame_display.resize(self.stereo_frame_display.sizeHint())
-
-        qpixmap = QPixmap.fromImage(q_image)
-        self.stereo_frame_display.setPixmap(qpixmap)
-        
-
-
-    def initiate_calibration(self):
-        def worker():
-            self.calibration_initiated.emit()
-            logger.info("Beginning wind-down process prior to calibration")
-            self.calibrate_collect_btn.setText("---calibrating---")
-            self.calibrate_collect_btn.setEnabled(False)
-            # self.frame_emitter.stop()
-            # self.stereo_frame_display.hide()
-            logger.info("Stop recording video")
-            self.session.stop_recording()
-            logger.info("Begin calibration")
-            logger.info("Pause synchronizer")
-            self.session.pause_synchronizer()
-            self.session.estimate_extrinsics()
-
-            self.possible_action = PossibleActions.CollectData
-            self.calibrate_collect_btn.setText(self.possible_action.value)
-            self.calibrate_collect_btn.setEnabled(True)
-            self.calibration_complete.emit()
-            logger.info("Calibration Complete signal sent...")
-            
-        self.init_calibration_thread = Thread(target=worker,args=(), daemon=True)
-        self.init_calibration_thread.start()
-
-class PairedFrameEmitter(QThread):
-    ImageBroadcast = Signal(QImage)
-    calibration_data_collected = Signal() 
-    possible_to_initialize_array = Signal()
-    
-    def __init__(self, paired_frame_builder:PairedFrameBuilder):
-        
-        super(PairedFrameEmitter,self).__init__()
-        self.paired_frame_builder = paired_frame_builder
-        logger.info("Initiated frame emitter")        
-        self.keep_collecting = Event() 
-        self.collection_complete = False
-
-    def wait_to_next_frame(self):
-        """
-        based on the next milestone time, return the time needed to sleep so that
-        a frame read immediately after would occur when needed
-        """
-        time = perf_counter()
-        fractional_time = time % 1
-        all_wait_times = self.paired_frame_builder.milestones - fractional_time
-        future_wait_times = all_wait_times[all_wait_times > 0]
-
-        if len(future_wait_times) == 0:
-            wait =  1 - fractional_time
-        else:
-            wait =  future_wait_times[0]
-        
-        sleep(wait)
-        
-    def run(self):
-
-        self.keep_collecting.set()
-        self.collection_complete = False
-
-        possible_to_initialize = False
-        
-        while self.keep_collecting.is_set():
-            
-            # that that it is important to make sure that this signal is sent only once
-            # to avoid multiple calibration attempts 
-            if len(self.paired_frame_builder.stereo_list) == 0 and not self.collection_complete:
-                logger.info("Signalling that calibration data is fully collected.")
-                self.collection_complete = True
-                self.calibration_data_collected.emit()
-            
-            if not possible_to_initialize:
-                # check to see if it is now
-                if self.paired_frame_builder.possible_to_initialize_array(MIN_THRESHOLD_FOR_EARLY_CALIBRATE):
-                    logger.info("Signaling that it is possible to initialize array based on collected data.")
-                    possible_to_initialize = True
-                    self.possible_to_initialize_array.emit()
-                      
-            stereo_frame = self.paired_frame_builder.get_stereo_frame()
-            self.wait_to_next_frame()
-            
-            if stereo_frame is not None:
-                image = cv2_to_qlabel(stereo_frame)
-                self.ImageBroadcast.emit(image)
-
-        logger.info("Stereoframe emitter run thread ended...") 
-            
-    # def stop(self):
-        # self.keep_collecting.clear() 
-
-
-        
-        
-        
-def cv2_to_qlabel(frame):
-    image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
-
-    qt_frame = QImage(
-        image.data,
-        image.shape[1],
-        image.shape[0],
-        QImage.Format.Format_RGB888,
-    )
-    return qt_frame
-
-    
-if __name__ == "__main__":
-        from caliscope.configurator import Configurator
-        from caliscope.trackers.charuco_tracker import CharucoTracker
-
-        App = QApplication(sys.argv)
-
-        session_path = Path(__root__, "dev","sample_sessions", "257")
-        configurator = Configurator(session_path)
-
-        session = LiveSession(configurator)
-        # session.load_cameras()
-        tracker = CharucoTracker(session.charuco)
-        session.load_stream_tools(tracker=tracker)
-
-
-        stereo_dialog = ExtrinsicCalibrationWidget(session)
-        stereo_dialog.show()
-
-        sys.exit(App.exec())
diff --git a/caliscope/gui/extrinsic_playback_widget.py b/caliscope/gui/extrinsic_playback_widget.py
index 966a4065..1be0fe01 100644
--- a/caliscope/gui/extrinsic_playback_widget.py
+++ b/caliscope/gui/extrinsic_playback_widget.py
@@ -1,62 +1,57 @@
-
-
-import caliscope.logger
-from time import sleep
 import math
 from threading import Event
-import numpy as np
+from time import sleep
 
 import cv2
-from PySide6.QtCore import Signal,Slot, QThread
+import numpy as np
+from PySide6.QtCore import QThread, Signal, Slot
 from PySide6.QtGui import QImage, QPixmap
 from PySide6.QtWidgets import (
     QGridLayout,
-    QWidget,
     QGroupBox,
     QHBoxLayout,
     QLabel,
     QVBoxLayout,
+    QWidget,
 )
 
+import caliscope.logger
 from caliscope.cameras.synchronizer import Synchronizer
-from caliscope.packets import FramePacket
 from caliscope.controller import Controller
+from caliscope.packets import FramePacket
 
 logger = caliscope.logger.get(__name__)
- 
-class ExtrinsicPlaybackWidget(QWidget):
-     
-    def __init__(self,controller:Controller):
 
+
+class ExtrinsicPlaybackWidget(QWidget):
+    def __init__(self, controller: Controller):
         super(ExtrinsicPlaybackWidget, self).__init__()
         self.controller = controller
-        self.synchronizer:Synchronizer = self.controller.synchronizer
+        self.synchronizer: Synchronizer = self.controller.synchronizer
         self.ports = self.synchronizer.ports
 
         # need to let synchronizer spin up before able to display frames
         while not hasattr(controller.synchronizer, "current_sync_packet"):
-            sleep(.25)
+            sleep(0.25)
         # create tools to build and emit the displayed frame
         # self.unpaired_frame_builder = FramePrepper(self.synchronizer)
         self.thumbnail_emitter = FrameDictionaryEmitter(self.synchronizer)
         self.thumbnail_emitter.start()
 
-        # all video output routed to qlabels stored in a dictionariy 
+        # all video output routed to qlabels stored in a dictionariy
         # make it as square as you can get it
-        self.playback_displays = {str(port):QLabel() for port in self.ports}
+        self.playback_displays = {str(port): QLabel() for port in self.ports}
         # self.recording_frame_display = QLabel()
-        
+
         self.place_widgets()
-        self.connect_widgets()        
-    
-        
+        self.connect_widgets()
 
     def place_widgets(self):
         self.setLayout(QVBoxLayout())
         self.settings_group = QGroupBox("Settings")
         self.settings_group.setLayout(QHBoxLayout())
         self.settings_group.layout().addWidget(QLabel("Frame Rate:"))
-        self.settings_group.layout().addWidget(self.frame_rate_spin)       
+        self.settings_group.layout().addWidget(self.frame_rate_spin)
         self.layout().addWidget(self.settings_group)
 
         self.record_controls = QGroupBox()
@@ -75,90 +70,86 @@ def place_widgets(self):
         self.layout().addLayout(dropped_fps_layout)
 
         camera_count = len(self.ports)
-        grid_columns = int(math.ceil(camera_count**.5))
-        grid_rows = int(math.ceil(camera_count/grid_columns))
+        grid_columns = int(math.ceil(camera_count**0.5))
+        # grid_rows = int(math.ceil(camera_count / grid_columns))
 
         frame_grid = QGridLayout()
         row = 0
-        column = 0        
+        column = 0
         for port in sorted(self.ports):
-            frame_grid.addWidget(self.playback_displays[str(port)], row,column)
-            
+            frame_grid.addWidget(self.playback_displays[str(port)], row, column)
+
             # update row and column for next iteration
-            if column >= grid_columns-1:
+            if column >= grid_columns - 1:
                 # start fresh on next row
                 column = 0
                 row += 1
             else:
                 column += 1
-            
+
         frame_display_layout = QHBoxLayout()
         frame_display_layout.addStretch(1)
         frame_display_layout.addLayout(frame_grid)
         frame_display_layout.addStretch(1)
         self.layout().addLayout(frame_display_layout)
 
-
     def connect_widgets(self):
-    
         self.thumbnail_emitter.ThumbnailImagesBroadcast.connect(self.ImageUpdateSlot)
         self.frame_rate_spin.valueChanged.connect(self.controller.set_active_mode_fps)
         self.thumbnail_emitter.dropped_fps.connect(self.update_dropped_fps)
         self.start_stop.clicked.connect(self.toggle_start_stop)
         self.controller.qt_signaler.recording_complete_signal.connect(self.on_recording_complete)
-        
-         
-    @Slot(dict) 
-    def ImageUpdateSlot(self, q_image_dict:dict):
+
+    @Slot(dict)
+    def ImageUpdateSlot(self, q_image_dict: dict):
         logger.debug("About to get qpixmap from qimage")
         for port, thumbnail in q_image_dict.items():
             qpixmap = QPixmap.fromImage(thumbnail)
             logger.debug("About to set qpixmap to display")
             self.playback_displays[port].setPixmap(qpixmap)
             logger.debug("successfully set display")
-        
+
 
 class FrameDictionaryEmitter(QThread):
     ThumbnailImagesBroadcast = Signal(dict)
     dropped_fps = Signal(dict)
-    
+
     def __init__(self, synchronizer: Synchronizer, single_frame_height=300):
-        
-        super(FrameDictionaryEmitter,self).__init__()
+        super(FrameDictionaryEmitter, self).__init__()
         self.single_frame_height = single_frame_height
         self.synchronizer = synchronizer
-        logger.info("Initiated recording frame emitter")        
-        self.keep_collecting = Event() 
-       
-    def run(self):
+        logger.info("Initiated recording frame emitter")
+        self.keep_collecting = Event()
 
+    def run(self):
         self.keep_collecting.set()
-        
+
         while self.keep_collecting.is_set():
             logger.debug("About to get next recording frame")
             # recording_frame = self.unpaired_frame_builder.get_recording_frame()
-            
+
             logger.debug("Referencing current sync packet in synchronizer")
             self.current_sync_packet = self.synchronizer.current_sync_packet
-        
-            thumbnail_qimage = {} 
+
+            thumbnail_qimage = {}
             for port in self.synchronizer.ports:
                 frame_packet = self.current_sync_packet.frame_packets[port]
                 rotation_count = self.synchronizer.streams[port].camera.rotation_count
 
-                text_frame = frame_packet_2_thumbnail(frame_packet, rotation_count, self.single_frame_height, port) 
+                text_frame = frame_packet_2_thumbnail(frame_packet, rotation_count, self.single_frame_height, port)
                 q_image = cv2_to_qimage(text_frame)
                 thumbnail_qimage[str(port)] = q_image
-            
+
             self.ThumbnailImagesBroadcast.emit(thumbnail_qimage)
-            
-            dropped_fps_dict = {str(port):dropped for port, dropped in self.synchronizer.dropped_fps.items()}
+
+            dropped_fps_dict = {str(port): dropped for port, dropped in self.synchronizer.dropped_fps.items()}
             self.dropped_fps.emit(dropped_fps_dict)
-        logger.info("Recording thumbnail emitter run thread ended...") 
-    
-def frame_packet_2_thumbnail(frame_packet:FramePacket, rotation_count:int, edge_length:int, port:int):
+        logger.info("Recording thumbnail emitter run thread ended...")
+
+
+def frame_packet_2_thumbnail(frame_packet: FramePacket, rotation_count: int, edge_length: int, port: int):
     raw_frame = get_frame_or_blank(frame_packet, edge_length)
-    # port = frame_packet.port        
+    # port = frame_packet.port
 
     # raw_frame = self.get_frame_or_blank(None)
     square_frame = resize_to_square(raw_frame, edge_length)
@@ -166,16 +157,17 @@ def frame_packet_2_thumbnail(frame_packet:FramePacket, rotation_count:int, edge_
     flipped_frame = cv2.flip(rotated_frame, 1)
 
     # put the port number on the top of the frame
-    text_frame = cv2.putText(flipped_frame,
-                        str(port),
-                        (int(flipped_frame.shape[1]/2), int(edge_length / 4)),
-                        fontFace=cv2.FONT_HERSHEY_SIMPLEX,
-                        fontScale=1,
-                        color=(0, 0, 255),
-                        thickness=2,
-                    )
+    text_frame = cv2.putText(
+        flipped_frame,
+        str(port),
+        (int(flipped_frame.shape[1] / 2), int(edge_length / 4)),
+        fontFace=cv2.FONT_HERSHEY_SIMPLEX,
+        fontScale=1,
+        color=(0, 0, 255),
+        thickness=2,
+    )
 
-    return text_frame        
+    return text_frame
 
 
 def get_frame_or_blank(frame_packet: FramePacket, edge_length):
@@ -190,6 +182,7 @@ def get_frame_or_blank(frame_packet: FramePacket, edge_length):
 
     return frame
 
+
 def resize_to_square(frame, edge_length):
     """To make sure that frames align well, scale them all to thumbnails
     squares with black borders."""
@@ -218,6 +211,7 @@ def resize_to_square(frame, edge_length):
     frame = resize(frame, new_height=edge_length)
     return frame
 
+
 def resize(image, new_height):
     (current_height, current_width) = image.shape[:2]
     ratio = new_height / float(current_height)
@@ -225,6 +219,7 @@ def resize(image, new_height):
     resized = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
     return resized
 
+
 def apply_rotation(frame, rotation_count):
     if rotation_count == 0:
         pass
@@ -237,14 +232,16 @@ def apply_rotation(frame, rotation_count):
 
     return frame
 
-     
-def prep_img_for_qpixmap(image:np.ndarray):
+
+def prep_img_for_qpixmap(image: np.ndarray):
     """
     qpixmap needs dimensions divisible by 4 and without that weird things happen.
     """
     if image.shape[1] % 4 != 0:  # If the width of the row isn't divisible by 4
         padding_width = 4 - (image.shape[1] % 4)  # Calculate how much padding is needed
-        padding = np.zeros((image.shape[0], padding_width, image.shape[2]), dtype=image.dtype)  # Create a black image of the required size
+        padding = np.zeros(
+            (image.shape[0], padding_width, image.shape[2]), dtype=image.dtype
+        )  # Create a black image of the required size
         image = np.hstack([image, padding])  # Add the padding to the right of the image
 
     return image
@@ -252,7 +249,7 @@ def prep_img_for_qpixmap(image:np.ndarray):
 
 def cv2_to_qimage(frame):
     image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
-    
+
     qt_frame = QImage(
         image.data,
         image.shape[1],
diff --git a/caliscope/gui/frame_emitters/frame_dictionary_emitter.py b/caliscope/gui/frame_emitters/frame_dictionary_emitter.py
index 229ee31c..6aa77e9b 100644
--- a/caliscope/gui/frame_emitters/frame_dictionary_emitter.py
+++ b/caliscope/gui/frame_emitters/frame_dictionary_emitter.py
@@ -1,14 +1,14 @@
-import caliscope.logger
-import numpy as np
-
-from threading import Event
 from queue import Queue
+from threading import Event
 
+import numpy as np
 from PySide6.QtCore import Qt, QThread, Signal
 from PySide6.QtGui import QPixmap
-from caliscope.cameras.synchronizer import Synchronizer
+
+import caliscope.logger
 from caliscope.cameras.camera_array import CameraData
-from caliscope.gui.frame_emitters.tools import resize_to_square, apply_rotation, cv2_to_qlabel
+from caliscope.cameras.synchronizer import Synchronizer
+from caliscope.gui.frame_emitters.tools import apply_rotation, cv2_to_qlabel, resize_to_square
 
 logger = caliscope.logger.get(__name__)
 
@@ -21,7 +21,7 @@ class FrameDictionaryEmitter(QThread):
     # GridCountBroadcast = Signal(int)
     # FrameIndexBroadcast = Signal(int, int)
 
-    def __init__(self, synchronizer: Synchronizer,all_camera_data:dict[CameraData], pixmap_edge_length=500):
+    def __init__(self, synchronizer: Synchronizer, all_camera_data: dict[CameraData], pixmap_edge_length=500):
         # pixmap_edge length is from the display window. Keep the display area
         # square to keep life simple.
         super(FrameDictionaryEmitter, self).__init__()
@@ -71,15 +71,13 @@ def run(self):
                         Qt.AspectRatioMode.KeepAspectRatio,
                     )
 
-                emitted_dict[str(port)] = pixmap               
+                emitted_dict[str(port)] = pixmap
 
             logger.debug(f"About to emit q_image_dict: {emitted_dict}")
-            self.FramesBroadcast.emit(emitted_dict) 
+            self.FramesBroadcast.emit(emitted_dict)
 
         self.close_window.emit()
-        logger.info(
-            f"Thread loop within frame emitter at port {self.synchronizer.port} successfully ended"
-        )
+        logger.info(f"Thread loop within frame emitter at port {self.synchronizer.port} successfully ended")
 
     def stop(self):
         self.keep_collecting = False
diff --git a/caliscope/gui/frame_emitters/playback_frame_emitter.py b/caliscope/gui/frame_emitters/playback_frame_emitter.py
index 990bf8ae..f3287d9c 100644
--- a/caliscope/gui/frame_emitters/playback_frame_emitter.py
+++ b/caliscope/gui/frame_emitters/playback_frame_emitter.py
@@ -1,15 +1,15 @@
-import caliscope.logger
-import numpy as np
-
-from threading import Event
 from queue import Queue
+from threading import Event
 
 import cv2
+import numpy as np
 from PySide6.QtCore import Qt, QThread, Signal
-from PySide6.QtGui import QImage, QPixmap
+from PySide6.QtGui import QPixmap
+
 import caliscope.calibration.draw_charuco as draw_charuco
+import caliscope.logger
+from caliscope.gui.frame_emitters.tools import apply_rotation, cv2_to_qlabel, resize_to_square
 from caliscope.recording.recorded_stream import RecordedStream
-from caliscope.gui.frame_emitters.tools import resize_to_square, apply_rotation, cv2_to_qlabel
 
 logger = caliscope.logger.get(__name__)
 
@@ -20,13 +20,13 @@ class PlaybackFrameEmitter(QThread):
     GridCountBroadcast = Signal(int)
     FrameIndexBroadcast = Signal(int, int)
 
-    def __init__(self, recorded_stream: RecordedStream,grid_history_q:Queue,  pixmap_edge_length=500): 
+    def __init__(self, recorded_stream: RecordedStream, grid_history_q: Queue, pixmap_edge_length=500):
         # pixmap_edge length is from the display window. Keep the display area
         # square to keep life simple.
         super(PlaybackFrameEmitter, self).__init__()
         self.stream = recorded_stream
         self.port = self.stream.port
-        
+
         # Apply a safety margin to the scaling factors (e.g., 5%)
         # used only when applying the undistortion
         self.scaling_factor = 1
@@ -44,8 +44,8 @@ def initialize_grid_capture_history(self):
         """
         The grid capture history is only used as a GUI element to display to the user
         the corners that have been collected and are being used in the calibration.
-        
-        It is not otherwise used in any calculations and needs to be re-initialized by 
+
+        It is not otherwise used in any calculations and needs to be re-initialized by
         the intrinsic stream manager whenever the intrinsic calibrators data is also
         re-initialized.
         """
@@ -63,9 +63,9 @@ def run(self):
             # self.monocalibrator.grid_frame_ready_q.get()
             logger.debug("Getting frame packet from queue")
             frame_packet = self.frame_packet_q.get()
-            
+
             while self.grid_history_q.qsize() > 0:
-                ids,img_loc = self.grid_history_q.get()
+                ids, img_loc = self.grid_history_q.get()
                 self.add_to_grid_history(ids, img_loc)
 
             if not self.keep_collecting.is_set():
@@ -75,9 +75,7 @@ def run(self):
                 self.frame = frame_packet.frame_with_points
 
                 logger.debug(f"Frame size is {self.frame.shape}")
-                logger.debug(
-                    f"Grid Capture History size is {self.grid_capture_history.shape}"
-                )
+                logger.debug(f"Grid Capture History size is {self.grid_capture_history.shape}")
                 self.frame = cv2.addWeighted(self.frame, 1, self.grid_capture_history, 1, 0)
 
                 self._apply_undistortion()
@@ -96,12 +94,8 @@ def run(self):
                     )
                 self.ImageBroadcast.emit(self.port, pixmap)
                 self.FrameIndexBroadcast.emit(self.port, frame_packet.frame_index)
-            
-
 
-        logger.info(
-            f"Thread loop within frame emitter at port {self.stream.port} successfully ended"
-        )
+        logger.info(f"Thread loop within frame emitter at port {self.stream.port} successfully ended")
 
     def stop(self):
         logger.info(f"Beginning to shut down frame emitter at port {self.port}")
@@ -109,36 +103,32 @@ def stop(self):
         self.keep_collecting.clear()
         self.frame_packet_q.put(-1)
         self.quit()
-        
+
     def set_scale_factor(self, scaling_factor):
         self.scaling_factor = scaling_factor
 
         if hasattr(self, "matrix") and hasattr(self, "distortions"):
-            self.update_distortion_params(self.undistort,self.matrix, self.distortions)
+            self.update_distortion_params(self.undistort, self.matrix, self.distortions)
 
     def update_distortion_params(self, undistort=None, matrix=None, distortions=None):
         if matrix is None:
             logger.info(f"No camera matrix calculated yet at port {self.port}")
         else:
-            logger.info(
-                f"Updating camera matrix and distortion parameters for frame emitter at port {self.port}"
-            )
-            
+            logger.info(f"Updating camera matrix and distortion parameters for frame emitter at port {self.port}")
+
             self.undistort = undistort
             self.matrix = matrix
             self.distortions = distortions
 
             h, w = self.stream.size
             # h, w = original_image_size
-            initial_new_matrix, valid_roi = cv2.getOptimalNewCameraMatrix(
-                self.matrix, self.distortions, (w, h), 1
-            )
+            initial_new_matrix, valid_roi = cv2.getOptimalNewCameraMatrix(self.matrix, self.distortions, (w, h), 1)
 
             logger.info(f"Valid ROI is {valid_roi}")
 
             # Find extreme points and midpoints in the original image
             corners = np.array([[0, 0], [0, h], [w, 0], [w, h]], dtype=np.float32)
-            midpoints = np.array([[w/2, 0], [w/2, h], [0, h/2], [w, h/2]], dtype=np.float32)
+            midpoints = np.array([[w / 2, 0], [w / 2, h], [0, h / 2], [w, h / 2]], dtype=np.float32)
             extreme_points = np.vstack((corners, midpoints))
 
             # Undistort these points
@@ -181,9 +171,7 @@ def _apply_undistortion(self):
         if self.undistort and self.matrix is not None:
             # Compute the optimal new camera matrix
             # Undistort the image
-            self.frame = cv2.undistort(
-                self.frame, self.matrix, self.distortions, None, self.new_matrix
-            )
+            self.frame = cv2.undistort(self.frame, self.matrix, self.distortions, None, self.new_matrix)
 
     def add_to_grid_history(self, ids, img_loc):
         """
@@ -202,5 +190,3 @@ def add_to_grid_history(self, ids, img_loc):
             )
         else:
             logger.info("Not enough points....grid not added...")
-
-
diff --git a/caliscope/gui/frame_emitters/tools.py b/caliscope/gui/frame_emitters/tools.py
index 7d489578..3fd2755c 100644
--- a/caliscope/gui/frame_emitters/tools.py
+++ b/caliscope/gui/frame_emitters/tools.py
@@ -1,10 +1,11 @@
 import cv2
-import numpy as np
 from PySide6.QtGui import QImage
+
 import caliscope.logger
 
 logger = caliscope.logger.get(__name__)
 
+
 def resize_to_square(frame):
     height = frame.shape[0]
     width = frame.shape[1]
@@ -28,7 +29,8 @@ def resize_to_square(frame):
 
     return frame
 
-def apply_rotation(frame, rotation_count:int):
+
+def apply_rotation(frame, rotation_count: int):
     if rotation_count == 0:
         pass
     elif rotation_count in [1, -3]:
@@ -52,4 +54,3 @@ def cv2_to_qlabel(frame):
         QImage.Format.Format_RGB888,
     )
     return qt_frame
-
diff --git a/caliscope/gui/log_widget.py b/caliscope/gui/log_widget.py
index 5a668fdd..7ba605dd 100644
--- a/caliscope/gui/log_widget.py
+++ b/caliscope/gui/log_widget.py
@@ -1,15 +1,16 @@
-from caliscope.logger import get, XStream
+from time import time
 
-from PySide6.QtCore import Slot, Qt
+from PySide6.QtCore import Qt, Slot
 from PySide6.QtWidgets import (
-    QWidget,
     QApplication,
-    QTextBrowser,
     QPushButton,
+    QTextBrowser,
     QVBoxLayout,
+    QWidget,
 )
 
-from time import time
+from caliscope.logger import XStream, get
+
 logger = get(__name__)
 
 
@@ -40,6 +41,7 @@ def __init__(self, message: str = None):
 def test():
     logger.info(f"This is a test; It is {time()}")
 
+
 class LogMessageViewer(QTextBrowser):
     def __init__(self, parent=None):
         super(LogMessageViewer, self).__init__(parent)
@@ -55,19 +57,18 @@ def appendLogMessage(self, msg):
         # scrollIsAtEnd = verScrollBar.maximum() - verScrollBar.value() <= 10
 
         verScrollBar.setValue(verScrollBar.maximum())  # Scrolls to the bottom
-        horScrollBar.setValue(0)  # scroll to the left  
+        horScrollBar.setValue(0)  # scroll to the left
         self.insertPlainText(msg)
 
         # if scrollIsAtEnd:
         #     verScrollBar.setValue(verScrollBar.maximum())  # Scrolls to the bottom
         #     self.insertPlainText(msg)
-        #     horScrollBar.setValue(0)  # scroll to the left  
+        #     horScrollBar.setValue(0)  # scroll to the left
+
 
 if __name__ == "__main__":
     app = QApplication([])
     dlg = LogWidget("This is only a test")
     dlg.show()
 
-    
-
     app.exec()
diff --git a/caliscope/gui/main_widget.py b/caliscope/gui/main_widget.py
index 9a6f5f40..14e6f33b 100644
--- a/caliscope/gui/main_widget.py
+++ b/caliscope/gui/main_widget.py
@@ -1,34 +1,35 @@
-import caliscope.logger
-from pathlib import Path
-from enum import Enum
 import os
-import sys
 import subprocess
+import sys
+from enum import Enum
+from pathlib import Path
+
+import rtoml
+from PySide6.QtCore import Qt
+from PySide6.QtGui import QAction, QIcon
 from PySide6.QtWidgets import (
     QApplication,
+    QDockWidget,
     QFileDialog,
     QMainWindow,
-    QWidget,
-    QTabWidget,
-    QDockWidget,
     QMenu,
+    QTabWidget,
+    QWidget,
 )
-import rtoml
-from PySide6.QtGui import QIcon, QAction
-from PySide6.QtCore import Qt
-from caliscope import __root__, __settings_path__
-from caliscope.gui.log_widget import LogWidget
-from caliscope.gui.charuco_widget import CharucoWidget
-from caliscope.gui.vizualize.calibration.capture_volume_widget import CaptureVolumeWidget
-from caliscope.gui.workspace_widget import WorkspaceSummaryWidget
+
+import caliscope.logger
+from caliscope import __log_dir__, __root__, __settings_path__
+from caliscope.cameras.camera_array import CameraArray
+from caliscope.controller import Controller
 from caliscope.gui.camera_management.multiplayback_widget import (
     MultiIntrinsicPlaybackWidget,
 )
+from caliscope.gui.charuco_widget import CharucoWidget
+from caliscope.gui.log_widget import LogWidget
 from caliscope.gui.post_processing_widget import PostProcessingWidget
-from caliscope.controller import Controller
-from caliscope import __log_dir__
 from caliscope.gui.vizualize.calibration.capture_volume_visualizer import CaptureVolumeVisualizer
-from caliscope.cameras.camera_array import CameraArray
+from caliscope.gui.vizualize.calibration.capture_volume_widget import CaptureVolumeWidget
+from caliscope.gui.workspace_widget import WorkspaceSummaryWidget
 
 logger = caliscope.logger.get(__name__)
 
@@ -51,13 +52,11 @@ def __init__(self):
         self.setMinimumSize(500, 500)
         self.central_tab = QWidget(self)
         self.setCentralWidget(self.central_tab)
-        
-        
+
         self.build_menus()
         self.connect_menu_actions()
         self.build_docked_logger()
 
-
     def connect_menu_actions(self):
         self.open_project_action.triggered.connect(self.create_new_project_folder)
         self.exit_pyxy3d_action.triggered.connect(QApplication.instance().quit)
@@ -97,10 +96,7 @@ def build_central_tabs(self):
         self.workspace_summary.reload_workspace_btn.clicked.connect(self.reload_workspace)
         self.central_tab.addTab(self.workspace_summary, "Workspace")
 
-        if (
-            self.controller.all_extrinsic_mp4s_available()
-            and self.controller.camera_array.all_intrinsics_calibrated()
-        ):
+        if self.controller.all_extrinsic_mp4s_available() and self.controller.camera_array.all_intrinsics_calibrated():
             self.workspace_summary.calibrate_btn.setEnabled(True)
         else:
             self.workspace_summary.calibrate_btn.setEnabled(False)
@@ -119,9 +115,7 @@ def build_central_tabs(self):
 
         logger.info("finished loading camera tab")
         self.central_tab.addTab(self.intrinsic_cal_widget, "Cameras")
-        self.central_tab.setTabEnabled(
-            self.find_tab_index_by_title("Cameras"), self.controller.cameras_loaded
-        )
+        self.central_tab.setTabEnabled(self.find_tab_index_by_title("Cameras"), self.controller.cameras_loaded)
         logger.info("Camera tab enabled")
 
         logger.info("About to load capture volume tab")
@@ -147,9 +141,7 @@ def build_central_tabs(self):
             self.post_processing_widget = QWidget()
             post_processing_enabled = False
         self.central_tab.addTab(self.post_processing_widget, "Post Processing")
-        self.central_tab.setTabEnabled(
-            self.find_tab_index_by_title("Post Processing"), post_processing_enabled
-        )
+        self.central_tab.setTabEnabled(self.find_tab_index_by_title("Post Processing"), post_processing_enabled)
 
     def build_docked_logger(self):
         # create log window which is fixed below main window
@@ -171,7 +163,6 @@ def launch_workspace(self, path_to_workspace: str):
         self.open_project_action.setEnabled(False)
         self.open_recent_project_submenu.setEnabled(False)
 
-
     def find_tab_index_by_title(self, title):
         # Iterate through tabs to find the index of the tab with the given title
         for index in range(self.central_tab.count()):
@@ -197,7 +188,6 @@ def reload_workspace(self):
         self.controller = Controller(workspace_dir=workspace)
         self.controller.load_workspace()
         self.controller.load_workspace_thread.finished.connect(self.build_central_tabs)
-        
 
     def add_to_recent_project(self, project_path: str):
         recent_project_action = QAction(project_path, self)
@@ -212,14 +202,14 @@ def open_recent_project(self):
 
     def open_log_dir(self):
         logger.info(f"Opening logging directory within File Explorer...  located at {__log_dir__}")
-        if sys.platform == 'win32':
+        if sys.platform == "win32":
             os.startfile(__log_dir__)
-        elif sys.platform == 'darwin':
+        elif sys.platform == "darwin":
             subprocess.run(["open", __log_dir__])
         else:  # Linux and Unix-like systems
             subprocess.run(["xdg-open", __log_dir__])
         pass
-        
+
     def create_new_project_folder(self):
         default_folder = Path(self.app_settings["last_project_parent"])
         dialog = QFileDialog()
@@ -254,7 +244,7 @@ def launch_main():
     import qdarktheme
 
     app = QApplication(sys.argv)
-    dummy_widget = CaptureVolumeVisualizer(camera_array=CameraArray({})) #  try to force "blinking to initial main"
+    dummy_widget = CaptureVolumeVisualizer(camera_array=CameraArray({}))  #  try to force "blinking to initial main"
     del dummy_widget
     qdarktheme.setup_theme("auto")
     window = MainWindow()
diff --git a/caliscope/gui/old_main_widget.py b/caliscope/gui/old_main_widget.py
deleted file mode 100644
index 8223627a..00000000
--- a/caliscope/gui/old_main_widget.py
+++ /dev/null
@@ -1,319 +0,0 @@
-import caliscope.logger
-from pathlib import Path
-
-
-from PySide6.QtWidgets import QMainWindow, QFileDialog
-from threading import Thread
-import sys
-from PySide6.QtWidgets import (
-    QApplication,
-    QMainWindow,
-    QWidget,
-    QDockWidget,
-    QMenu,
-)
-import rtoml
-from PySide6.QtGui import QIcon, QAction
-from PySide6.QtCore import Qt
-from caliscope import __root__, __settings_path__
-from caliscope.session.session import LiveSession, SessionMode
-from caliscope.gui.log_widget import LogWidget
-from caliscope.configurator import Configurator
-from caliscope.gui.charuco_widget import CharucoWidget
-from caliscope.gui.live_camera_config.intrinsic_calibration_widget import (
-    IntrinsicCalibrationWidget,
-)
-from caliscope.gui.recording_widget import RecordingWidget
-from caliscope.gui.post_processing_widget import PostProcessingWidget
-from caliscope.gui.extrinsic_calibration_widget import ExtrinsicCalibrationWidget
-from caliscope.gui.vizualize.calibration.capture_volume_widget import CaptureVolumeWidget
-
-logger = caliscope.logger.get(__name__)
-
-
-class MainWindow(QMainWindow):
-    def __init__(self):
-        super(MainWindow, self).__init__()
-
-        self.app_settings = rtoml.load(__settings_path__)
-
-        self.setWindowTitle("Caliscope")
-        self.setWindowIcon(QIcon(str(Path(__root__, "caliscope/gui/icons/pyxy_logo.svg"))))
-        self.setMinimumSize(500, 500)
-
-        # File Menu
-        self.menu = self.menuBar()
-
-        # CREATE FILE MENU
-        self.file_menu = self.menu.addMenu("&File")
-        self.open_project_action = QAction("New/Open Project", self)
-        self.file_menu.addAction(self.open_project_action)
-
-        # Open Recent
-        self.open_recent_project_submenu = QMenu("Recent Projects...", self)
-        # Populate the submenu with recent project paths;
-        # reverse so that last one appended is at the top of the list
-        for project_path in reversed(self.app_settings["recent_projects"]):
-            self.add_to_recent_project(project_path)
-
-        self.file_menu.addMenu(self.open_recent_project_submenu)
-
-        self.exit_pyxy3d_action = QAction("Exit", self)
-        self.file_menu.addAction(self.exit_pyxy3d_action)
-
-        # CREATE CAMERA MENU
-        self.cameras_menu = self.menu.addMenu("&Cameras")
-        self.connect_cameras_action = QAction("Co&nnect Cameras", self)
-        self.cameras_menu.addAction(self.connect_cameras_action)
-        self.connect_cameras_action.setEnabled(False)
-
-        self.disconnect_cameras_action = QAction("&Disconnect Cameras", self)
-        self.cameras_menu.addAction(self.disconnect_cameras_action)
-        self.disconnect_cameras_action.setEnabled(False)
-
-        # CREATE MODE MENU
-        self.mode_menu = self.menu.addMenu("&Mode")
-        self.charuco_mode_select = QAction(SessionMode.Charuco.value)
-        self.intrinsic_mode_select = QAction(SessionMode.IntrinsicCalibration.value)
-        self.extrinsic_mode_select = QAction(SessionMode.ExtrinsicCalibration.value)
-        self.capture_volume_mode_select = QAction(SessionMode.CaptureVolumeOrigin.value)
-        self.recording_mode_select = QAction(SessionMode.Recording.value)
-        self.triangulate_mode_select = QAction(SessionMode.Triangulate.value)
-        self.mode_menu.addAction(self.charuco_mode_select)
-        self.mode_menu.addAction(self.intrinsic_mode_select)
-        self.mode_menu.addAction(self.extrinsic_mode_select)
-        self.mode_menu.addAction(self.capture_volume_mode_select)
-        self.mode_menu.addAction(self.recording_mode_select)
-        self.mode_menu.addAction(self.triangulate_mode_select)
-
-        for action in self.mode_menu.actions():
-            action.setEnabled(False)
-
-        self.connect_menu_actions()
-        self.blank_widget = QWidget()
-        self.setCentralWidget(self.blank_widget)
-
-        # create log window which is fixed below main window
-        self.docked_logger = QDockWidget("Log", self)
-        self.docked_logger.setFeatures(QDockWidget.DockWidgetFeature.DockWidgetMovable)
-        self.docked_logger.setAllowedAreas(Qt.DockWidgetArea.BottomDockWidgetArea)
-        self.log_widget = LogWidget()
-        self.docked_logger.setWidget(self.log_widget)
-
-        self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.docked_logger)
-
-    def connect_menu_actions(self):
-        self.open_project_action.triggered.connect(self.create_new_project_folder)
-        self.connect_cameras_action.triggered.connect(self.load_stream_tools)
-        self.exit_pyxy3d_action.triggered.connect(QApplication.instance().quit)
-        self.disconnect_cameras_action.triggered.connect(self.disconnect_cameras)
-
-        for action in self.mode_menu.actions():
-            action.triggered.connect(self.mode_change_action)
-
-    def mode_change_action(self):
-        action = self.sender()
-
-        # create a reverse lookup dictionary to pull the mode enum that should be activated
-        SessionModeLookup = {mode.value: mode for mode in SessionMode}
-        mode = SessionModeLookup[action.text()]
-        logger.info(f"Attempting to set session mode to {mode.value}")
-        self.session.set_mode(mode)
-        logger.info(f"Successful change to {mode} Mode")
-
-    def update_central_widget_mode(self):
-        """
-        This will be triggered whenever the session successfully completes a mode change and emits
-        a signal to that effect.
-        """
-        logger.info("Begin process of updating central widget")
-
-        old_widget = self.centralWidget()
-        self.setCentralWidget(QWidget())
-        old_widget.deleteLater()
-
-        logger.info("Clearing events in emmitter threads to get them to wind down")
-        if type(old_widget) == RecordingWidget:
-            old_widget.thumbnail_emitter.keep_collecting.clear()
-            logger.info("Waiting for recording widget to wrap up")
-            old_widget.thumbnail_emitter.wait()
-
-        if type(old_widget) == ExtrinsicCalibrationWidget:
-            old_widget.paired_frame_emitter.keep_collecting.clear()
-            logger.info("Waiting for extrinsic calibration widget to wrap up")
-            old_widget.paired_frame_emitter.wait()
-
-        if type(old_widget) == IntrinsicCalibrationWidget:
-            for port, tab in old_widget.camera_tabs.tab_widgets.items():
-                tab.frame_emitter.keep_collecting.clear()
-
-        logger.info(f"Matching next tab to active session mode: {self.session.mode}")
-        # Create the new central widget based on the mode
-        match self.session.mode:
-            case SessionMode.Charuco:
-                new_widget = CharucoWidget(self.session)
-            case SessionMode.IntrinsicCalibration:
-                new_widget = IntrinsicCalibrationWidget(self.session)
-            case SessionMode.ExtrinsicCalibration:
-                logger.info("About to create extrinsic calibration widget")
-                new_widget = ExtrinsicCalibrationWidget(self.session)
-            case SessionMode.CaptureVolumeOrigin:
-                new_widget = CaptureVolumeWidget(self.session)
-            case SessionMode.Recording:
-                new_widget = RecordingWidget(self.session)
-            case SessionMode.Triangulate:
-                new_widget = PostProcessingWidget(self.session)
-
-        self.setCentralWidget(new_widget)
-
-    def switch_to_capture_volume(self):
-        """
-        Once the extrinsic calibration is complete, the GUI should automatically switch over to the capture volume widget
-        """
-        self.session.set_mode(SessionMode.CaptureVolumeOrigin)
-
-    def update_enable_disable(self):
-        # note: if the cameras are connected,then you can peak
-        # into extrinsic/recording tabs, though cannot collect data
-
-        # you can always look at a charuco board
-        self.charuco_mode_select.setEnabled(True)
-
-        if self.session.is_camera_setup_eligible():
-            self.intrinsic_mode_select.setEnabled(True)
-            self.extrinsic_mode_select.setEnabled(True)
-            self.recording_mode_select.setEnabled(True)
-        else:
-            self.intrinsic_mode_select.setEnabled(False)
-            self.extrinsic_mode_select.setEnabled(False)
-            self.recording_mode_select.setEnabled(False)
-
-        if self.session.is_capture_volume_eligible():
-            self.capture_volume_mode_select.setEnabled(True)
-        else:
-            self.capture_volume_mode_select.setEnabled(False)
-
-        if self.session.is_triangulate_eligible():
-            self.triangulate_mode_select.setEnabled(True)
-        else:
-            self.triangulate_mode_select.setEnabled(False)
-
-    def disconnect_cameras(self):
-        self.session.set_mode(SessionMode.Charuco)
-        self.session.disconnect_cameras()
-        self.disconnect_cameras_action.setEnabled(False)
-        self.connect_cameras_action.setEnabled(True)
-        self.update_enable_disable()
-
-    def pause_all_frame_reading(self):
-        logger.info(
-            "Pausing all frame reading at load of stream tools; should be on charuco tab right now"
-        )
-        self.session.pause_all_monocalibrators()
-        self.session.pause_synchronizer()
-
-    def load_stream_tools(self):
-        self.connect_cameras_action.setEnabled(False)
-        self.disconnect_cameras_action.setEnabled(True)
-        self.session.qt_signaler.stream_tools_loaded_signal.connect(
-            self.pause_all_frame_reading
-        )
-        self.thread = Thread(
-            target=self.session.load_stream_tools, args=(), daemon=True
-        )
-        self.thread.start()
-
-    def launch_session(self, path_to_folder: str):
-        session_path = Path(path_to_folder)
-        self.config = Configurator(session_path)
-        logger.info(f"Launching session with config file stored in {session_path}")
-        self.session = LiveSession(self.config)
-
-        # can always load charuco
-        self.charuco_widget = CharucoWidget(self.session)
-        self.setCentralWidget(self.charuco_widget)
-
-        # now connecting to cameras is an option
-        self.connect_cameras_action.setEnabled(True)
-
-        # but must exit and start over to launch a new session for now
-        self.connect_session_signals()
-
-        self.open_project_action.setEnabled(False)
-        self.open_recent_project_submenu.setEnabled(False)
-        self.update_enable_disable()
-
-    def connect_session_signals(self):
-        """
-        After launching a session, connect signals and slots.
-        Much of these will be from the GUI to the session and vice-versa
-        """
-        self.session.qt_signaler.unlock_postprocessing.connect(
-            self.update_enable_disable
-        )
-        self.session.qt_signaler.mode_change_success.connect(
-            self.update_central_widget_mode
-        )
-        self.session.qt_signaler.stream_tools_loaded_signal.connect(
-            self.update_enable_disable
-        )
-        self.session.qt_signaler.stream_tools_disconnected_signal.connect(
-            self.update_enable_disable
-        )
-        self.session.qt_signaler.mode_change_success.connect(self.update_enable_disable)
-        self.session.qt_signaler.extrinsic_calibration_complete.connect(
-            self.switch_to_capture_volume
-        )
-
-    def add_to_recent_project(self, project_path: str):
-        recent_project_action = QAction(project_path, self)
-        recent_project_action.triggered.connect(self.open_recent_project)
-        self.open_recent_project_submenu.addAction(recent_project_action)
-
-    def open_recent_project(self):
-        action = self.sender()
-        project_path = action.text()
-        logger.info(f"Opening recent session stored at {project_path}")
-        self.launch_session(project_path)
-
-    def create_new_project_folder(self):
-        default_folder = Path(self.app_settings["last_project_parent"])
-        dialog = QFileDialog()
-        path_to_folder = dialog.getExistingDirectory(
-            parent=None,
-            caption="Open Previous or Create New Project Directory",
-            dir=str(default_folder),
-            options=QFileDialog.Option.ShowDirsOnly,
-        )
-
-        if path_to_folder:
-            logger.info(("Creating new project in :", path_to_folder))
-            self.add_project_to_recent(path_to_folder)
-            self.launch_session(path_to_folder)
-
-    def add_project_to_recent(self, folder_path):
-        if str(folder_path) in self.app_settings["recent_projects"]:
-            pass
-        else:
-            self.app_settings["recent_projects"].append(str(folder_path))
-            self.app_settings["last_project_parent"] = str(Path(folder_path).parent)
-            self.update_app_settings()
-            self.add_to_recent_project(folder_path)
-
-    def update_app_settings(self):
-        with open(__settings_path__, "w") as f:
-            rtoml.dump(self.app_settings, f)
-
-
-def launch_main():
-    import qdarktheme
-
-    app = QApplication(sys.argv)
-    qdarktheme.setup_theme("auto")
-    window = MainWindow()
-    window.show()
-    app.exec()
-
-
-if __name__ == "__main__":
-    launch_main()
diff --git a/caliscope/gui/post_processing_widget.py b/caliscope/gui/post_processing_widget.py
index f612add0..96ae1159 100644
--- a/caliscope/gui/post_processing_widget.py
+++ b/caliscope/gui/post_processing_widget.py
@@ -1,43 +1,44 @@
-import caliscope.logger
-
-
 from pathlib import Path
-import pandas as pd
-from caliscope.trackers.tracker_enum import TrackerEnum
 
-from PySide6.QtCore import Signal, QUrl
+import pandas as pd
+from PySide6.QtCore import QUrl, Signal
 from PySide6.QtGui import QDesktopServices
 from PySide6.QtWidgets import (
-    QMessageBox,
-    QWidget,
     QComboBox,
-    QListWidget,
     QHBoxLayout,
     QLabel,
+    QListWidget,
+    QMessageBox,
     QPushButton,
     QVBoxLayout,
+    QWidget,
 )
-from caliscope.post_processing.blender_tools import generate_metarig_config
-from caliscope.controller import Controller
+
+import caliscope.logger
 from caliscope.configurator import Configurator
+from caliscope.controller import Controller
 from caliscope.gui.vizualize.playback_triangulation_widget import (
     PlaybackTriangulationWidget,
 )
+from caliscope.post_processing.blender_tools import generate_metarig_config
+from caliscope.trackers.tracker_enum import TrackerEnum
+
 logger = caliscope.logger.get(__name__)
 
+
 class PostProcessingWidget(QWidget):
     processing_complete = Signal()
 
-    def __init__(self, controller:Controller):
+    def __init__(self, controller: Controller):
         super(PostProcessingWidget, self).__init__()
-        self.controller = controller 
+        self.controller = controller
         self.config = self.controller.config
 
         self.sync_index_cursors = {}  # track where the slider is for each playback...
         self.recording_folders = QListWidget()
         self.update_recording_folders()
 
-        self.vis_widget = PlaybackTriangulationWidget(self.controller.camera_array)  
+        self.vis_widget = PlaybackTriangulationWidget(self.controller.camera_array)
 
         self.tracker_combo = QComboBox()
         self.vizualizer_title = QLabel()
@@ -47,28 +48,16 @@ def __init__(self, controller:Controller):
             if tracker.name != "CHARUCO":
                 self.tracker_combo.addItem(tracker.name, tracker)
 
-
         self.open_folder_btn = QPushButton("&Open Folder")
         self.process_current_btn = QPushButton("&Process")
         self.generate_metarig_config_btn = QPushButton("Generate Metarig Config")
-        self.refresh_visualizer() # must happen before placement to create vis_widget and vizualizer_title
+        self.refresh_visualizer()  # must happen before placement to create vis_widget and vizualizer_title
         self.place_widgets()
         self.connect_widgets()
-        
 
     def set_current_xyz(self):
-
         if self.xyz_processed_path.exists():
             self.vis_widget.update_motion_trial(self.xyz_processed_path)
-            # # confirm that there are some triangulated values to observe
-            # xyz = pd.read_csv(self.xyz_processed_path)
-            # if xyz.shape[0] != 0:
-            #     logger.info(f"Setting xyz display coordinates to those stored in {self.xyz_processed_path}")
-            #     self.xyz = xyz
-            # else:
-            #     logger.info("Not enough data to triangulate points")
-            #     QMessageBox.warning(self, "Warning", f"The {self.active_tracker_enum.name} tracker did not identify sufficient points for triangulation to occur for recordings stored in:\n{self.active_recording_path}.") # show a warning dialog
-            #     self.xyz = None
         else:
             logger.info(f"No points displayed; Nothing stored in {self.xyz_processed_path}")
             # self.xyz = None
@@ -78,8 +67,11 @@ def set_current_xyz(self):
                 xy = pd.read_csv(self.xy_base_path)
                 if xy.shape[0] == 0:
                     logger.info("No points tracked")
-                    QMessageBox.warning(self, "Warning", f"The {self.active_tracker_enum.name} tracker did not identify any points to track in recordings stored in:\n{self.active_recording_path}.") # show a warning dialog
-
+                    QMessageBox.warning(
+                        self,
+                        "Warning",
+                        f"The {self.active_tracker_enum.name} tracker did not identify any points to track in recordings stored in:\n{self.active_recording_path}.",  # noqa 501
+                    )  # show a warning dialog
 
     def update_recording_folders(self):
         # this check here is an artifact of the way that the main widget handles refresh
@@ -90,8 +82,8 @@ def update_recording_folders(self):
         # add each folder to the QListWidget
         for folder in dir_list:
             self.recording_folders.addItem(folder)
-        
-        if len(dir_list)>0:
+
+        if len(dir_list) > 0:
             self.recording_folders.setCurrentRow(0)
 
     @property
@@ -112,7 +104,6 @@ def xyz_processed_path(self):
     @property
     def archived_config_path(self):
         return Path(self.processed_subfolder, "config.toml")
-        
 
     @property
     def xy_base_path(self):
@@ -123,13 +114,12 @@ def xy_base_path(self):
     @property
     def active_tracker_enum(self):
         return self.tracker_combo.currentData()
-        
+
     @property
     def metarig_config_path(self):
         file_name = f"metarig_config_{self.tracker_combo.currentData().name}.json"
         result = Path(self.processed_subfolder, file_name)
         return result
-        
 
     @property
     def active_folder(self):
@@ -140,15 +130,15 @@ def active_folder(self):
             active_folder: str = self.recording_folders.currentItem().text()
         else:
             active_folder: str = self.recording_folders.currentItem().text()
-            
+
         return active_folder
 
     @property
-    def active_recording_path(self)-> Path:
+    def active_recording_path(self) -> Path:
         p = Path(self.controller.workspace_guide.recording_dir, self.active_folder)
         logger.info(f"Active recording path is {p}")
-        return p        
-        
+        return p
+
     @property
     def viz_title_html(self):
         if self.xyz_processed_path.exists():
@@ -156,7 +146,7 @@ def viz_title_html(self):
         else:
             suffix = "(no processed data)"
 
-        title = f"<div align='center'><b>{self.tracker_combo.currentData().name.title()} Tracker: {self.active_folder} {suffix} </b></div>"
+        title = f"<div align='center'><b>{self.tracker_combo.currentData().name.title()} Tracker: {self.active_folder} {suffix} </b></div>"  # noqa E501
 
         return title
 
@@ -201,33 +191,35 @@ def open_folder(self):
             url = QUrl.fromLocalFile(str(folder_path))
             QDesktopServices.openUrl(url)
         else:
-            logger.warn("No folder selected")
+            logger.warning("No folder selected")
 
     def process_current(self):
         """
-        
+
         This needs to get pushed into the controller layer
         """
         recording_path = Path(self.controller.workspace_guide.recording_dir, self.active_folder)
         logger.info(f"Beginning processing of recordings at {recording_path}")
         tracker_enum = self.tracker_combo.currentData()
         logger.info(f"(x,y) tracking will be applied using {tracker_enum.name}")
-        recording_config_toml  = Path(recording_path,"config.toml")
+        recording_config_toml = Path(recording_path, "config.toml")
         logger.info(f"Camera data based on config file saved to {recording_config_toml}")
 
         self.controller.process_recordings(recording_path, tracker_enum)
 
     def active_tracker_config_path(self):
         """
-        This will exist of the tracker has been processed. It should have a camera array within it 
-        that can be displayed to the user and will align 
+        This will exist of the tracker has been processed. It should have a camera array within it
+        that can be displayed to the user and will align
         """
-        return Path(self.active_recording_path,self.active_tracker_enum.name, "config.toml")
-        
+        return Path(self.active_recording_path, self.active_tracker_enum.name, "config.toml")
+
     def refresh_visualizer(self):
         logger.info("Refreshing vizualizer within post_processing widget")
-        
-        if self.archived_config_path.exists():  # processing has been done and their is a camera array that can be loaded
+
+        if (
+            self.archived_config_path.exists()
+        ):  # processing has been done and their is a camera array that can be loaded
             stored_config = Configurator(self.archived_config_path.parent)
             presented_camera_array = stored_config.get_camera_array()
         else:
@@ -235,7 +227,6 @@ def refresh_visualizer(self):
 
         self.vis_widget.update_camera_array(presented_camera_array)
 
-        
         self.set_current_xyz()
         self.vizualizer_title.setText(self.viz_title_html)
         self.update_enabled_disabled()
@@ -260,25 +251,31 @@ def enable_all_inputs(self):
         self.vis_widget.slider.setEnabled(True)
 
     def update_enabled_disabled(self):
-        # set availability of metarig generation 
+        # set availability of metarig generation
         logger.info("Checking if metarig config can be created...")
         tracker = self.tracker_combo.currentData().value()
         logger.info(tracker)
-        if (tracker.metarig_mapped and self.xyz_processed_path.exists() and not self.metarig_config_path.exists()):
+        if tracker.metarig_mapped and self.xyz_processed_path.exists() and not self.metarig_config_path.exists():
             self.generate_metarig_config_btn.setEnabled(True)
             self.generate_metarig_config_btn.setToolTip("Creation of metarig configuration file is now available")
         else:
             self.generate_metarig_config_btn.setEnabled(False)
-        
+
         if not tracker.metarig_mapped:
             self.generate_metarig_config_btn.setToolTip("Tracker is not set up to scale to a metarig")
         elif self.metarig_config_path.exists():
-            self.generate_metarig_config_btn.setToolTip("The Metarig configuration json file has already been created.Check the tracker subfolder in the recording directory.")
+            self.generate_metarig_config_btn.setToolTip(
+                "The Metarig configuration json file has already been created. Check the tracker subfolder in the recording directory."  # noqa E501
+            )
         elif not self.xyz_processed_path.exists():
-            self.generate_metarig_config_btn.setToolTip("Must process recording to create xyz estimates for metarig configuration")
+            self.generate_metarig_config_btn.setToolTip(
+                "Must process recording to create xyz estimates for metarig configuration"
+            )
         else:
-            self.generate_metarig_config_btn.setToolTip("Click to create a file in the tracker subfolder that can be used to scale a Blender metarig")
-        # set availability of Proecssing and slider                
+            self.generate_metarig_config_btn.setToolTip(
+                "Click to create a file in the tracker subfolder that can be used to scale a Blender metarig"
+            )
+        # set availability of Proecssing and slider
         if self.xyz_processed_path.exists():
             self.process_current_btn.setEnabled(False)
             self.vis_widget.slider.setEnabled(True)
@@ -286,7 +283,7 @@ def update_enabled_disabled(self):
             # nothing available to triangulate
             self.process_current_btn.setEnabled(False)
             self.vis_widget.slider.setEnabled(False)
-            
+
         else:
             self.process_current_btn.setEnabled(True)
             self.vis_widget.slider.setEnabled(False)
@@ -300,11 +297,9 @@ def update_slider_position(self):
         else:
             pass
 
-
     def create_metarig_config(self):
         logger.info(f"Beginning metarig_config creation in {self.processed_subfolder}")
         tracker_enum = self.tracker_combo.currentData()
         xyz_csv_path = Path(self.processed_subfolder, f"xyz_{tracker_enum.name}_labelled.csv")
         generate_metarig_config(tracker_enum, xyz_csv_path)
         self.update_enabled_disabled()
-
diff --git a/caliscope/gui/progress_dialog.py b/caliscope/gui/progress_dialog.py
index 30473514..fea0b04e 100644
--- a/caliscope/gui/progress_dialog.py
+++ b/caliscope/gui/progress_dialog.py
@@ -1,12 +1,12 @@
-from PySide6.QtWidgets import QLabel, QDialog, QProgressBar, QVBoxLayout
 from PySide6.QtCore import Qt
+from PySide6.QtWidgets import QDialog, QLabel, QProgressBar, QVBoxLayout
 
 
 class ProgressDialog(QDialog):
     def __init__(self, parent=None):
         super().__init__(parent)
 
-        self.setWindowTitle('Landmark Tracking and Triangulation')
+        self.setWindowTitle("Landmark Tracking and Triangulation")
 
         self.display_text = QLabel()
         self.progress_bar = QProgressBar(self)
@@ -19,11 +19,9 @@ def __init__(self, parent=None):
         layout.addWidget(self.display_text)
         layout.addWidget(self.progress_bar)
 
-    def update(self, data:dict):
+    def update(self, data: dict):
         if "close" in data.keys():
             self.hide()
         else:
             self.display_text.setText(data["stage"])
             self.progress_bar.setValue(data["percent"])
-
-
diff --git a/caliscope/gui/synched_frames_display.py b/caliscope/gui/synched_frames_display.py
index d2cfa424..78a38efb 100644
--- a/caliscope/gui/synched_frames_display.py
+++ b/caliscope/gui/synched_frames_display.py
@@ -1,21 +1,17 @@
-import caliscope.logger
-from time import sleep
 import math
+from time import sleep
 
-from PySide6.QtCore import Slot, Qt
-from PySide6.QtGui import QPixmap
+from PySide6.QtCore import Qt, Slot
 from PySide6.QtWidgets import (
     QGridLayout,
-    QMainWindow,
-    QWidget,
-    QScrollArea,
-    QLineEdit,
     QHBoxLayout,
     QLabel,
+    QScrollArea,
     QVBoxLayout,
+    QWidget,
 )
 
-from caliscope.cameras.synchronizer import Synchronizer
+import caliscope.logger
 from caliscope.gui.frame_emitters.frame_dictionary_emitter import FrameDictionaryEmitter
 from caliscope.synchronized_stream_manager import SynchronizedStreamManager
 
@@ -24,10 +20,10 @@
 
 class SynchedFramesDisplay(QWidget):
     """
-    This widget is not intended to have any interactive functionality at all and to only 
+    This widget is not intended to have any interactive functionality at all and to only
     provide a window to the user of the current landmark tracking
-    
-    This is why the primary input is the sync stream manager directly and not the controller 
+
+    This is why the primary input is the sync stream manager directly and not the controller
     Apologies to Future Mac who is reading this and regretting my decisions.
     """
 
@@ -35,11 +31,10 @@ def __init__(self, sync_stream_manager: SynchronizedStreamManager):
         super(SynchedFramesDisplay, self).__init__()
 
         self.setWindowTitle("Tracking Landmarks....")
-        self.sync_stream_manager = sync_stream_manager 
+        self.sync_stream_manager = sync_stream_manager
         self.synchronizer = self.sync_stream_manager.synchronizer
         self.ports = self.synchronizer.ports
 
-
         while not hasattr(sync_stream_manager.synchronizer, "current_sync_packet"):
             logger.info("Waiting for synchronizer to have sync packet")
             sleep(0.25)
@@ -88,7 +83,7 @@ def place_widgets(self):
         scroll_viewport = QWidget()
         scroll_viewport.setLayout(padded_grid_layout)
 
-        #Scroll Area Properties
+        # Scroll Area Properties
         self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
         self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
         self.scroll_area.setWidgetResizable(True)
@@ -96,7 +91,7 @@ def place_widgets(self):
         # self.setCentralWidget(self.scroll_area)
         self.setLayout(QVBoxLayout())
         self.layout().addWidget(self.scroll_area)
-    
+
     def connect_widgets(self):
         self.frame_dictionary_emitter.FramesBroadcast.connect(self.ImageUpdateSlot)
         # self.frame_dictionary_emitter.dropped_fps.connect(self.update_dropped_fps)
@@ -118,5 +113,3 @@ def ImageUpdateSlot(self, qpixmaps: dict):
             logger.debug("About to set qpixmap to display")
             self.recording_displays[str(port)].setPixmap(qpixmap)
             logger.debug("successfully set display")
-
-    
\ No newline at end of file
diff --git a/caliscope/gui/vizualize/calibration/capture_volume_visualizer.py b/caliscope/gui/vizualize/calibration/capture_volume_visualizer.py
index 5ad57ca7..95d83613 100644
--- a/caliscope/gui/vizualize/calibration/capture_volume_visualizer.py
+++ b/caliscope/gui/vizualize/calibration/capture_volume_visualizer.py
@@ -1,16 +1,14 @@
-import caliscope.logger
-
-
 import numpy as np
 import pyqtgraph.opengl as gl
 
-
-from caliscope.gui.vizualize.camera_mesh import CameraMesh, mesh_from_camera
-from caliscope.cameras.camera_array import CameraArray
+import caliscope.logger
 from caliscope.calibration.capture_volume.capture_volume import CaptureVolume
+from caliscope.cameras.camera_array import CameraArray
+from caliscope.gui.vizualize.camera_mesh import CameraMesh, mesh_from_camera
 
 logger = caliscope.logger.get(__name__)
 
+
 class CaptureVolumeVisualizer:
     """
     Can except either a single camera array or a capture volume that includes
@@ -18,10 +16,7 @@ class CaptureVolumeVisualizer:
     be played back.
     """
 
-    def __init__(
-        self, capture_volume: CaptureVolume = None, camera_array: CameraArray = None
-    ):
-
+    def __init__(self, capture_volume: CaptureVolume = None, camera_array: CameraArray = None):
         if camera_array is not None and capture_volume is None:
             self.camera_array = camera_array
             self.point_estimates = None
@@ -49,7 +44,7 @@ def refresh_scene(self):
         for port, cam in self.camera_array.cameras.items():
             print(port)
             print(cam)
-            mesh:CameraMesh = mesh_from_camera(cam)
+            mesh: CameraMesh = mesh_from_camera(cam)
             self.meshes[port] = mesh
             self.scene.addItem(mesh)
 
@@ -69,10 +64,10 @@ def refresh_scene(self):
 
             self.min_sync_index = np.min(self.sync_indices)
             self.max_sync_index = np.max(self.sync_indices)
-   
+
             if self.sync_index is not None:
                 self.display_points(self.sync_index)
-                 
+
     def display_points(self, sync_index):
         """
         sync_index is provided from the dialog and linked to the slider
@@ -80,18 +75,13 @@ def display_points(self, sync_index):
         """
         self.sync_index = sync_index
         current_sync_index_flag = self.point_estimates.sync_indices == sync_index
-        single_board_indices = np.unique(
-            self.point_estimates.obj_indices[current_sync_index_flag]
-        )
-
+        single_board_indices = np.unique(self.point_estimates.obj_indices[current_sync_index_flag])
 
         self.single_board_points = self.point_estimates.obj[single_board_indices]
-        self.mean_board_position = np.mean(self.single_board_points,axis=0)
+        self.mean_board_position = np.mean(self.single_board_points, axis=0)
         logger.debug(f"Mean Board Position at sync index {sync_index}: {self.mean_board_position}")
 
         self.scatter.setData(pos=self.single_board_points)
 
 
-
-
-# %%
\ No newline at end of file
+# %%
diff --git a/caliscope/gui/vizualize/calibration/capture_volume_widget.py b/caliscope/gui/vizualize/calibration/capture_volume_widget.py
index 415597fa..42133608 100644
--- a/caliscope/gui/vizualize/calibration/capture_volume_widget.py
+++ b/caliscope/gui/vizualize/calibration/capture_volume_widget.py
@@ -1,11 +1,7 @@
-import caliscope.logger
-
-import numpy as np
-
 from PySide6.QtCore import Qt
 from PySide6.QtWidgets import (
-    QGroupBox,
     QGridLayout,
+    QGroupBox,
     QHBoxLayout,
     QLabel,
     QPushButton,
@@ -14,6 +10,7 @@
     QWidget,
 )
 
+import caliscope.logger
 from caliscope.controller import Controller
 from caliscope.gui.vizualize.calibration.capture_volume_visualizer import (
     CaptureVolumeVisualizer,
@@ -47,11 +44,8 @@ def __init__(self, controller: Controller):
         self.rotate_z_plus_btn = QPushButton("Z+")
         self.rotate_z_minus_btn = QPushButton("Z-")
 
-        # self.distance_error_summary = QLabel(self.session.quality_controller.distance_error_summary.to_string(index=False))
         self.rmse_summary = QLabel(self.controller.capture_volume.get_rmse_summary())
 
-        # self.recalibrate_btn = QPushButton("Recalibrate")
-
         self.place_widgets()
         self.connect_widgets()
 
@@ -91,17 +85,11 @@ def connect_widgets(self):
         self.slider.valueChanged.connect(self.visualizer.display_points)
         self.set_origin_btn.clicked.connect(self.set_origin_to_board)
         self.rotate_x_plus_btn.clicked.connect(lambda: self.rotate_capture_volume("x+"))
-        self.rotate_x_minus_btn.clicked.connect(
-            lambda: self.rotate_capture_volume("x-")
-        )
+        self.rotate_x_minus_btn.clicked.connect(lambda: self.rotate_capture_volume("x-"))
         self.rotate_y_plus_btn.clicked.connect(lambda: self.rotate_capture_volume("y+"))
-        self.rotate_y_minus_btn.clicked.connect(
-            lambda: self.rotate_capture_volume("y-")
-        )
+        self.rotate_y_minus_btn.clicked.connect(lambda: self.rotate_capture_volume("y-"))
         self.rotate_z_plus_btn.clicked.connect(lambda: self.rotate_capture_volume("z+"))
-        self.rotate_z_minus_btn.clicked.connect(
-            lambda: self.rotate_capture_volume("z-")
-        )
+        self.rotate_z_minus_btn.clicked.connect(lambda: self.rotate_capture_volume("z-"))
 
     def set_origin_to_board(self):
         logger.info("Setting origin to board...")
diff --git a/caliscope/gui/vizualize/camera_mesh.py b/caliscope/gui/vizualize/camera_mesh.py
index 22015076..4bd224b6 100644
--- a/caliscope/gui/vizualize/camera_mesh.py
+++ b/caliscope/gui/vizualize/camera_mesh.py
@@ -1,79 +1,82 @@
+import math
 
-import caliscope.logger
-
+import numpy as np
 import pyqtgraph as pg
 import pyqtgraph.opengl as gl
-import math
 
+import caliscope.logger
 from caliscope.cameras.camera_array import CameraData
-import numpy as np
+
 logger = caliscope.logger.get(__name__)
 
+
 class CameraMesh:
     """Build a camera mesh object that is looking up from the origin"""
+
     def __init__(self, res, cam_matrix, scale_factor=5000):
-        
         # self.scene = scene
 
-        self.width = res[0]/scale_factor
-        self.height = res[1]/scale_factor
-        self.fx = cam_matrix[0][0]/scale_factor
-        self.fy = cam_matrix[1][1]/scale_factor
-        self.cx = cam_matrix[0][2]/scale_factor
-        self.cy = cam_matrix[1][2]/scale_factor
+        self.width = res[0] / scale_factor
+        self.height = res[1] / scale_factor
+        self.fx = cam_matrix[0][0] / scale_factor
+        self.fy = cam_matrix[1][1] / scale_factor
+        self.cx = cam_matrix[0][2] / scale_factor
+        self.cy = cam_matrix[1][2] / scale_factor
 
-        self.f_mean = (self.fx+self.fy)/2 # mean focal length...height of inverted pyramid
+        self.f_mean = (self.fx + self.fy) / 2  # mean focal length...height of inverted pyramid
 
         self.build_verts()
         self.build_faces()
         self.build_colors()
 
-        self.mesh = gl.GLMeshItem(vertexes=self.verts, 
-                                  faces=self.faces, 
-                                  faceColors=self.colors, 
-                                  smooth=False, 
-                                  drawEdges=True, 
-                                  edgeColor=(0,0,1,1))
-        self.mesh.setGLOptions('additive')
+        self.mesh = gl.GLMeshItem(
+            vertexes=self.verts,
+            faces=self.faces,
+            faceColors=self.colors,
+            smooth=False,
+            drawEdges=True,
+            edgeColor=(0, 0, 1, 1),
+        )
+        self.mesh.setGLOptions("additive")
 
         logger.debug(self.verts)
         logger.debug(self.faces)
         logger.debug(self.colors)
 
     def build_verts(self):
-        right_side_border = self.width-self.cx
+        right_side_border = self.width - self.cx
         left_side_border = -self.cx
-        top_side_border = self.height-self.cy
+        top_side_border = self.height - self.cy
         bottom_side_border = -self.cy
         pyramid_height = self.f_mean
 
-        self.verts = [[0,    0,     0],   #0: focal point at origin
-                      [right_side_border,top_side_border,pyramid_height],         #1: top right of image
-                      [right_side_border,bottom_side_border,pyramid_height],         #2: bottom right of image
-                      [left_side_border,bottom_side_border,pyramid_height],         #3: bottom left of image
-                      [left_side_border,top_side_border,pyramid_height]]         #4: top left of image
+        self.verts = [
+            [0, 0, 0],  # 0: focal point at origin
+            [right_side_border, top_side_border, pyramid_height],  # 1: top right of image
+            [right_side_border, bottom_side_border, pyramid_height],  # 2: bottom right of image
+            [left_side_border, bottom_side_border, pyramid_height],  # 3: bottom left of image
+            [left_side_border, top_side_border, pyramid_height],
+        ]  # 4: top left of image
 
-        self.verts = np.array(self.verts)      
+        self.verts = np.array(self.verts)
 
     def build_faces(self):
-        self.faces = [[0,1,2],
-                      [0,2,3],
-                      [0,3,4],
-                      [0,4,1],
-                      [1,2,3],
-                      [3,4,1]]
+        self.faces = [[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [1, 2, 3], [3, 4, 1]]
 
         self.faces = np.array(self.faces)
 
     def build_colors(self):
-        self.colors = [[.5,1,0,.2],
-                       [.5,1,0,.2],
-                       [.5,1,0,.2],
-                       [.5,1,0,.2],
-                       [0,0,0,.9],
-                       [0,0,0,.9]]
+        self.colors = [
+            [0.5, 1, 0, 0.2],
+            [0.5, 1, 0, 0.2],
+            [0.5, 1, 0, 0.2],
+            [0.5, 1, 0, 0.2],
+            [0, 0, 0, 0.9],
+            [0, 0, 0, 0.9],
+        ]
+
+        self.colors = np.array(self.colors)
 
-        self.colors = np.array(self.colors)        
 
 def rotation_to_float(rotation_matrix):
     new_matrix = []
@@ -120,7 +123,6 @@ def mesh_from_camera(camera_data: CameraData):
 
 
 def rotationMatrixToEulerAngles(R):
-
     sy = math.sqrt(R[0, 0] * R[0, 0] + R[1, 0] * R[1, 0])
 
     singular = sy < 1e-6
@@ -136,15 +138,17 @@ def rotationMatrixToEulerAngles(R):
 
     return np.array([x, y, z])
 
-if __name__ == '__main__':
-    import rtoml
+
+if __name__ == "__main__":
     from pathlib import Path
-    
+
+    import rtoml
+
     app = pg.mkQApp("GLMeshItem Example")
 
     scene = gl.GLViewWidget()
     scene.show()
-    scene.setWindowTitle('Camera Calibration')
+    scene.setWindowTitle("Camera Calibration")
     scene.setCameraPosition(distance=4)
 
     # grid = gl.GLGridItem()
@@ -153,17 +157,15 @@ def rotationMatrixToEulerAngles(R):
     axis = gl.GLAxisItem()
     scene.addItem(axis)
 
-
-    repo = Path(str(Path(__file__)).split("pyxy")[0],"pyxy")
+    repo = Path(str(Path(__file__)).split("pyxy")[0], "pyxy")
     # config_path = r"config 2.toml"
     config = rtoml.load(Path(repo, "sessions", "iterative_adjustment", "config.toml"))
-    cams = {}    
+    cams = {}
     ports = []
 
     # build cameras
     for key, params in config.items():
         if "cam" in key:
-
             res = params["resolution"]
             cam_matrix = params["camera_matrix"]
             port = params["port"]
@@ -177,23 +179,22 @@ def rotationMatrixToEulerAngles(R):
 
             print(key)
             print(params)
-    
+
     # need to track frame of reference for each camera posiiton
     # must be able ot iterate over each frame of reference
     # place cameras
 
-
     origin_port = 0
-    cams[origin_port].mesh.setGLOptions('additive')
-    scene.addItem(cams[origin_port].mesh)    
+    cams[origin_port].mesh.setGLOptions("additive")
+    scene.addItem(cams[origin_port].mesh)
 
     for key, params in config.items():
         if "stereo" in key:
             pair = key.split("_")[1:3]
             pair = [int(p) for p in pair]
-            
+
             if origin_port in pair:
-                for param_key, value in params.items(): 
+                for param_key, value in params.items():
                     if "translation" in param_key:
                         translation = [float(x[0]) for x in value]
                         translation_scale = 1
@@ -205,31 +206,31 @@ def rotationMatrixToEulerAngles(R):
                         else:
                             other_port = pair[1]
 
-                        x,y,z = [t/translation_scale for t in translation]
-                        cams[other_port].mesh.translate(x,y,z)
+                        x, y, z = [t / translation_scale for t in translation]
+                        cams[other_port].mesh.translate(x, y, z)
                         logger.info(f"Translation: x: {x}, y: {y}, z: {z}")
                         # cams[other_port].mesh.setGLOptions('additive')
 
                         scene.addItem(cams[other_port].mesh)
                     if "rotation" in param_key:
-                        rotation_count = rotation_to_float(value) # feeding in 3x3 rotation matrix  from config file
-                        rotation_count = rotationMatrixToEulerAngles(rotation_count) # convert to angles
+                        rotation_count = rotation_to_float(value)  # feeding in 3x3 rotation matrix  from config file
+                        rotation_count = rotationMatrixToEulerAngles(rotation_count)  # convert to angles
                         if origin_port == pair[1]:
                             rotation_count = -rotation_count
                             other_port = pair[0]
                         else:
                             other_port = pair[1]
 
-                        rot_deg = [x*(180/math.pi) for x in rotation_count] # convert to degrees
+                        rot_deg = [x * (180 / math.pi) for x in rotation_count]  # convert to degrees
                         print(f"Rotation (deg) for port {other_port}: {rot_deg}")
                         x = rot_deg[0]
                         y = rot_deg[1]
                         z = rot_deg[2]
 
                         logger.info(f"ROTATION: x: {x}, y: {y}, z: {z}")
-                        cams[other_port].mesh.rotate(x,1,0,0, local=True)
-                        cams[other_port].mesh.rotate(y,0,1,0, local=True)
-                        cams[other_port].mesh.rotate(z,0,0,1, local=True)
+                        cams[other_port].mesh.rotate(x, 1, 0, 0, local=True)
+                        cams[other_port].mesh.rotate(y, 0, 1, 0, local=True)
+                        cams[other_port].mesh.rotate(z, 0, 0, 1, local=True)
                         # cams[other_port].mesh.setGLOptions('additive')
 
                         scene.addItem(cams[other_port].mesh)
diff --git a/caliscope/gui/vizualize/playback_triangulation_widget.py b/caliscope/gui/vizualize/playback_triangulation_widget.py
index 94383a15..54798536 100644
--- a/caliscope/gui/vizualize/playback_triangulation_widget.py
+++ b/caliscope/gui/vizualize/playback_triangulation_widget.py
@@ -1,23 +1,24 @@
 from pathlib import Path
-import numpy as np
 from time import time
-import pyqtgraph.opengl as gl
 
+import numpy as np
+import pyqtgraph.opengl as gl
 from PySide6.QtCore import Qt
 from PySide6.QtWidgets import (
     QSlider,
     QVBoxLayout,
     QWidget,
 )
-from caliscope.gui.vizualize.camera_mesh import CameraMesh, mesh_from_camera
-from caliscope.cameras.camera_array import CameraArray
-import caliscope.logger
 
+import caliscope.logger
+from caliscope.cameras.camera_array import CameraArray
+from caliscope.gui.vizualize.camera_mesh import CameraMesh, mesh_from_camera
 from caliscope.motion_trial import MotionTrial
 
 logger = caliscope.logger.get(__name__)
 # as part of development process I'm just going to import the skeleton in here
 
+
 class PlaybackTriangulationWidget(QWidget):
     def __init__(self, camera_array: CameraArray, xyz_history_path: Path = None):
         super(PlaybackTriangulationWidget, self).__init__()
@@ -67,7 +68,6 @@ def update_camera_array(self, camera_array: CameraArray):
 
 
 class TriangulationVisualizer:
-
     def __init__(self, camera_array: CameraArray):
         self.camera_array = camera_array
         self.build_scene()
@@ -82,7 +82,7 @@ def build_scene(self):
             self.scene = gl.GLViewWidget()
 
             # the scene camera, not a real Camera
-            self.scene.setCameraPosition( distance=4)  
+            self.scene.setCameraPosition(distance=4)
         axis = gl.GLAxisItem()
         self.scene.addItem(axis)
 
@@ -99,10 +99,10 @@ def build_scene(self):
             size=0.01,
             pxMode=False,
         )
-        
-            # will hold a list
+
+        # will hold a list
         self.segments = {}
-        
+
         self.scene.addItem(self.scatter)
         self.scatter.setData(pos=None)
 
@@ -110,10 +110,10 @@ def update_camera_array(self, camera_array: CameraArray):
         self.camera_array = camera_array
         self.build_scene()
 
-    def update_motion_trial(self, motion_trial:MotionTrial):
+    def update_motion_trial(self, motion_trial: MotionTrial):
         logger.info("Updating xyz history in playback widget")
-        self.motion_trial:MotionTrial = motion_trial
-        
+        self.motion_trial: MotionTrial = motion_trial
+
         if hasattr(self.motion_trial.tracker, "wireframe"):
             for segment_line in self.motion_trial.tracker.wireframe.line_plots.values():
                 self.scene.addItem(segment_line)
@@ -121,8 +121,7 @@ def update_motion_trial(self, motion_trial:MotionTrial):
         self.sync_index = self.motion_trial.start_index
         self.display_points(self.sync_index)
 
-
-    def display_points(self, sync_index:int):
+    def display_points(self, sync_index: int):
         """
         sync_index is provided from the dialog and linked to the slider
         it is initially set to the minimum viable sync index
@@ -136,6 +135,5 @@ def display_points(self, sync_index:int):
             xyz_coords = self.motion_trial.get_xyz(self.sync_index).point_xyz
             self.scatter.setData(pos=xyz_coords)
 
-
-    def update_segment_lines(self,sync_index:int):
-        self.motion_trial.update_wireframe(sync_index)
\ No newline at end of file
+    def update_segment_lines(self, sync_index: int):
+        self.motion_trial.update_wireframe(sync_index)
diff --git a/caliscope/gui/workspace_widget.py b/caliscope/gui/workspace_widget.py
index 84ff96e3..962effb2 100644
--- a/caliscope/gui/workspace_widget.py
+++ b/caliscope/gui/workspace_widget.py
@@ -1,18 +1,19 @@
 import os
-from caliscope.gui.synched_frames_display import SynchedFramesDisplay
-from PySide6.QtCore import QThread
-import sys
 import subprocess
-import time
-from pathlib import Path
-from PySide6.QtWidgets import QHBoxLayout, QLabel, QWidget, QVBoxLayout, QPushButton, QSpinBox, QGridLayout, QTextBrowser
-from PySide6.QtCore import QFileSystemWatcher, Slot, Qt
-from caliscope.controller import Controller
+import sys
+
+from PySide6.QtCore import QFileSystemWatcher, Qt
+from PySide6.QtWidgets import QGridLayout, QHBoxLayout, QLabel, QPushButton, QSpinBox, QTextBrowser, QWidget
+
 import caliscope.logger
+from caliscope.controller import Controller
+from caliscope.gui.synched_frames_display import SynchedFramesDisplay
+
 logger = caliscope.logger.get(__name__)
 
+
 class WorkspaceSummaryWidget(QWidget):
-    def __init__(self, controller:Controller):
+    def __init__(self, controller: Controller):
         super().__init__()
 
         self.controller = controller
@@ -33,24 +34,27 @@ def __init__(self, controller:Controller):
         self.connect_widgets()
 
         self.update_status()
-        
-        
+
     def place_widgets(self):
         # Layout
         self.layout = QGridLayout()
         self.setLayout(self.layout)
-        self.layout.addWidget(self.status_HTML,0,0,1,4)
+        self.layout.addWidget(self.status_HTML, 0, 0, 1, 4)
 
         camera_spin_layout = QHBoxLayout()
         camera_spin_layout.addWidget(QLabel("Cameras:"), alignment=Qt.AlignmentFlag.AlignRight)
         camera_spin_layout.addWidget(self.camera_count_spin, alignment=Qt.AlignmentFlag.AlignLeft)
-        self.layout.addLayout(camera_spin_layout,1,0,)
-        self.layout.addWidget(self.reload_workspace_btn, 1,1)
-        self.layout.addWidget(self.open_workspace_folder_btn, 1,2)
-        self.layout.addWidget(self.calibrate_btn,1,3)
-        
+        self.layout.addLayout(
+            camera_spin_layout,
+            1,
+            0,
+        )
+        self.layout.addWidget(self.reload_workspace_btn, 1, 1)
+        self.layout.addWidget(self.open_workspace_folder_btn, 1, 2)
+        self.layout.addWidget(self.calibrate_btn, 1, 3)
+
     def connect_widgets(self):
-        self.open_workspace_folder_btn.clicked.connect(self.open_workspace)  
+        self.open_workspace_folder_btn.clicked.connect(self.open_workspace)
         self.calibrate_btn.clicked.connect(self.on_calibrate_btn_clicked)
         self.camera_count_spin.valueChanged.connect(self.set_camera_count)
         self.controller.show_synched_frames.connect(self.show_synched_frames)
@@ -62,12 +66,12 @@ def on_calibrate_btn_clicked(self):
 
     def set_camera_count(self, value):
         self.controller.set_camera_count(value)
-        
+
     def open_workspace(self):
         logger.info(f"Opening workspace within File Explorer...  located at {self.controller.workspace}")
-        if sys.platform == 'win32':
+        if sys.platform == "win32":
             os.startfile(self.controller.workspace)
-        elif sys.platform == 'darwin':
+        elif sys.platform == "darwin":
             subprocess.run(["open", self.controller.workspace])
         else:  # Linux and Unix-like systems
             subprocess.run(["xdg-open", self.controller.workspace])
@@ -76,6 +80,6 @@ def show_synched_frames(self):
         logger.info("About to launch synced Frames Display")
         self.display_window = SynchedFramesDisplay(self.controller.extrinsic_stream_manager)
         self.display_window.show()
-                
+
     def update_status(self):
-        self.status_HTML.setHtml(self.controller.workspace_guide.get_html_summary())
\ No newline at end of file
+        self.status_HTML.setHtml(self.controller.workspace_guide.get_html_summary())
diff --git a/caliscope/helper.py b/caliscope/helper.py
index 304bb7a5..029f77a0 100644
--- a/caliscope/helper.py
+++ b/caliscope/helper.py
@@ -1,32 +1,30 @@
+import shutil
+from pathlib import Path
+
 import caliscope.logger
 
-from pathlib import Path
-import shutil
 logger = caliscope.logger.get(__name__)
 
+
 def copy_contents(src_folder, dst_folder):
     """
-    Helper function to port a test case data folder over to a temp directory 
+    Helper function to port a test case data folder over to a temp directory
     used for testing purposes so that the test case data doesn't get overwritten
     """
     src_path = Path(src_folder)
     dst_path = Path(dst_folder)
 
-
     if dst_path.exists():
         shutil.rmtree(dst_path)
-        
+
     # Create the destination folder if it doesn't exist
     dst_path.mkdir(parents=True, exist_ok=False)
 
-
-        
     for item in src_path.iterdir():
         # Construct the source and destination paths
         src_item = src_path / item
         dst_item = dst_path / item.name
 
-
         # Copy file or directory
         if src_item.is_file():
             logger.info(f"Copying file at {src_item} to {dst_item}")
diff --git a/caliscope/intrinsic_stream_manager.py b/caliscope/intrinsic_stream_manager.py
index 280117e5..c8ae1a76 100644
--- a/caliscope/intrinsic_stream_manager.py
+++ b/caliscope/intrinsic_stream_manager.py
@@ -1,12 +1,13 @@
-import caliscope.logger
-from time import sleep
 from pathlib import Path
-from caliscope.recording.recorded_stream import RecordedStream
-from caliscope.trackers.charuco_tracker import CharucoTracker
+from time import sleep
+
+import caliscope.logger
+from caliscope.calibration.intrinsic_calibrator import IntrinsicCalibrator
 from caliscope.cameras.camera_array import CameraData
-from caliscope.packets import Tracker
 from caliscope.gui.frame_emitters.playback_frame_emitter import PlaybackFrameEmitter
-from caliscope.calibration.intrinsic_calibrator import IntrinsicCalibrator
+from caliscope.packets import Tracker
+from caliscope.recording.recorded_stream import RecordedStream
+from caliscope.trackers.charuco_tracker import CharucoTracker
 
 logger = caliscope.logger.get(__name__)
 
@@ -132,11 +133,13 @@ def autocalibrate(self, port, grid_count, pct_board_threshold):
         board_corners = self.tracker.charuco.board.getChessboardCorners()
         total_corner_count = board_corners.shape[0]
         threshold_corner_count = total_corner_count * pct_board_threshold
-        threshold_corner_count = max(threshold_corner_count,6)   # additional requirement that I believe is part of the alogrithm
+        threshold_corner_count = max(
+            threshold_corner_count, 6
+        )  # additional requirement that I believe is part of the alogrithm
 
         logger.info(f"Corners for charuco are {board_corners}")
 
-        # calculate basic wait time between board collections 
+        # calculate basic wait time between board collections
         # if many frames have incomplete data, this will fail to reach the target board count
         start_frame_index = stream.start_frame_index
         last_frame_index = stream.last_frame_index
@@ -159,5 +162,5 @@ def autocalibrate(self, port, grid_count, pct_board_threshold):
         while intrinsic_calibrator.grid_count < grid_count:
             logger.info(f"Waiting for sufficient calibration boards to become populated at port {port}")
             sleep(2)
-        
-        intrinsic_calibrator.calibrate_camera()
\ No newline at end of file
+
+        intrinsic_calibrator.calibrate_camera()
diff --git a/caliscope/logger.py b/caliscope/logger.py
index b624b843..3ccef987 100644
--- a/caliscope/logger.py
+++ b/caliscope/logger.py
@@ -1,17 +1,18 @@
-# Construct a single logger that will be used throughout 
+# Construct a single logger that will be used throughout
 # Detail will be logged to a single file with INFO logged to the console
 
 import logging
-from PySide6 import QtCore
-import sys
 import os
+import sys
 from pathlib import Path
-from caliscope import __log_dir__
 
+from PySide6 import QtCore
+
+from caliscope import __log_dir__
 
 # only one file handler accross package so all messages logged to one file
 
-app_dir_file_handler = logging.FileHandler(Path(__log_dir__,'calibration.log'), "w+")
+app_dir_file_handler = logging.FileHandler(Path(__log_dir__, "calibration.log"), "w+")
 app_dir_file_handler.setLevel(logging.INFO)
 
 file_log_format = " %(levelname)8s| %(name)30s| %(lineno)3d|  %(message)s"
@@ -22,7 +23,7 @@
 console_handler = logging.StreamHandler()
 console_handler.setLevel(logging.INFO)
 
-console_log_format =" %(levelname)8s| %(name)30s| %(lineno)3d|  %(message)s"
+console_log_format = " %(levelname)8s| %(name)30s| %(lineno)3d|  %(message)s"
 console_formatter = logging.Formatter(console_log_format)
 console_handler.setFormatter(console_formatter)
 
@@ -32,66 +33,71 @@
 class QtHandler(logging.Handler):
     """
     Adapted from discussion here: https://stackoverflow.com/questions/24469662/how-to-redirect-logger-output-into-pyqt-text-widget
-    This handler will allow a QDialog box to pick up the logger output which may be useful for a  
+    This handler will allow a QDialog box to pick up the logger output which may be useful for a
     splash screen to show users that something is happening during big processing moments like:
     - loading/finding cameras
 
     - building / unbuilding synchronizer
     - performing stereocalibration
     """
+
     def __init__(self):
         logging.Handler.__init__(self)
         # qt_log_format =" %(levelname)s| %(name)s |%(message)s"
-        qt_log_format =" %(name)s|%(message)s"
+        qt_log_format = " %(name)s|%(message)s"
         qt_formatter = logging.Formatter(qt_log_format)
         self.setFormatter(qt_formatter)
 
     def emit(self, record):
         record = self.format(record)
-        if record: XStream.stdout().write(f"{record} \n")
+        if record:
+            XStream.stdout().write(f"{record} \n")
 
 
 class XStream(QtCore.QObject):
     _stdout = None
     _stderr = None
     messageWritten = QtCore.Signal(str)
-    def flush( self ):
+
+    def flush(self):
         pass
-    def fileno( self ):
+
+    def fileno(self):
         return -1
-    def write( self, msg ):
-        if ( not self.signalsBlocked() ):
+
+    def write(self, msg):
+        if not self.signalsBlocked():
             self.messageWritten.emit(msg)
 
     @staticmethod
     def stdout():
-        if ( not XStream._stdout ):
+        if not XStream._stdout:
             XStream._stdout = XStream()
             sys.stdout = XStream._stdout
         return XStream._stdout
 
     @staticmethod
     def stderr():
-        if ( not XStream._stderr ):
+        if not XStream._stderr:
             XStream._stderr = XStream()
             sys.stderr = XStream._stderr
         return XStream._stderr
 
-def get(name): # as in __name__
+
+def get(name):  # as in __name__
     logger = logging.getLogger(name)
 
-    logger.setLevel(logging.INFO) 
-    
+    logger.setLevel(logging.INFO)
+
     logger.addHandler(app_dir_file_handler)
     logger.addHandler(console_handler)
- 
-    # avoid stepping through XStream object if in debug 
-    if os.getenv("DEBUG") != '1':
+
+    # avoid stepping through XStream object if in debug
+    if os.getenv("DEBUG") != "1":
         qt_handler = QtHandler()
         logger.addHandler(qt_handler)
-    
+
     # qt_handler = QtHandler()
     # logger.addHandler(qt_handler)
 
     return logger
-
diff --git a/caliscope/motion_trial.py b/caliscope/motion_trial.py
index 9e073d56..d99d4b43 100644
--- a/caliscope/motion_trial.py
+++ b/caliscope/motion_trial.py
@@ -1,19 +1,22 @@
+from dataclasses import dataclass, field
 from pathlib import Path
+
+import numpy as np
 import pandas as pd
-from dataclasses import dataclass, field
+
 from caliscope.packets import XYZPacket
-import numpy as np
 from caliscope.trackers.tracker_enum import TrackerEnum
 
+
 @dataclass
 class MotionTrial:
     """
     Motion trial loaded in from output csv
     """
 
-    xyz_csv: Path    
-    xyz_packets:  dict = field(default_factory=dict[int:XYZPacket])
-    
+    xyz_csv: Path
+    xyz_packets: dict = field(default_factory=dict[int:XYZPacket])
+
     def __post_init__(self):
         # assert(isinstance(self.xyz_csv,Path))
         # assert(self.xyz_csv.exists())
@@ -32,29 +35,29 @@ def __post_init__(self):
         self.start_index = sync_indices.min()
         self.end_index = sync_indices.max()
         self.xyz_packets = {}
-                
-        if len(sync_indices) ==0:
+
+        if len(sync_indices) == 0:
             self.is_empty = True
         else:
             self.is_empty = False
 
-    def get_xyz(self,sync_index:int)->XYZPacket:
+    def get_xyz(self, sync_index: int) -> XYZPacket:
         """
         Cache packets as they are initially read off
         """
         if sync_index not in self.xyz_packets:
             current_sync_index = self.xyz_df["sync_index"] == sync_index
             point_ids = self.xyz_df["point_id"][current_sync_index]
-                
+
             x = self.xyz_df["x_coord"][current_sync_index]
-            y = self.xyz_df["y_coord"][current_sync_index]               
+            y = self.xyz_df["y_coord"][current_sync_index]
             z = self.xyz_df["z_coord"][current_sync_index]
 
-            xyz = np.column_stack([x,y,z])
-            self.xyz_packets[sync_index] = XYZPacket(sync_index=sync_index, point_ids=point_ids,point_xyz=xyz)
+            xyz = np.column_stack([x, y, z])
+            self.xyz_packets[sync_index] = XYZPacket(sync_index=sync_index, point_ids=point_ids, point_xyz=xyz)
 
         return self.xyz_packets[sync_index]
-    
-    def update_wireframe(self, sync_index:int):
+
+    def update_wireframe(self, sync_index: int):
         xyz_packet = self.get_xyz(sync_index)
-        self.wireframe.set_points(xyz_packet)
\ No newline at end of file
+        self.wireframe.set_points(xyz_packet)
diff --git a/caliscope/packets.py b/caliscope/packets.py
index d933c09a..a3bf1fb4 100644
--- a/caliscope/packets.py
+++ b/caliscope/packets.py
@@ -1,8 +1,9 @@
+from abc import ABC, abstractmethod
 from dataclasses import dataclass
+
+import cv2
 import numpy as np
 from numba.typed import List
-from abc import ABC, abstractmethod
-import cv2
 
 
 @dataclass(frozen=True, slots=True)
@@ -15,13 +16,9 @@ class PointPacket:
     It has actual values when using the Charuco tracker as these are used in the calibration.
     """
 
-    point_id: np.ndarray = (
-        None  # unique point id that aligns with Tracker.get_point_names()
-    )
+    point_id: np.ndarray = None  # unique point id that aligns with Tracker.get_point_names()
     img_loc: np.ndarray = None  # x,y position of tracked point
-    obj_loc: np.ndarray = (
-        None  # x,y,z in object frame of reference; primarily for calibration
-    )
+    obj_loc: np.ndarray = None  # x,y,z in object frame of reference; primarily for calibration
     confidence: np.ndarray = None  # may be available in some trackers..include for potentnial downstream calculations
 
     @property
@@ -53,9 +50,7 @@ def name(self) -> str:
         pass
 
     @abstractmethod
-    def get_points(
-        self, frame: np.ndarray, port: int, rotation_count: int
-    ) -> PointPacket:
+    def get_points(self, frame: np.ndarray, port: int, rotation_count: int) -> PointPacket:
         """
         frame: np.ndarray from reading an OpenCV capture object
 
@@ -126,9 +121,7 @@ def metarig_symmetrical_measures(self):
         left_pointA,left_pointB and right_pointA, right_pointB will be calculated.
         The mean of the two sides will be taken
         """
-        raise NotImplementedError(
-            f"Tracker {self.name} has not provided its measures for configuring a metarig"
-        )
+        raise NotImplementedError(f"Tracker {self.name} has not provided its measures for configuring a metarig")
 
     @property
     def metarig_bilateral_measures(self):
@@ -136,11 +129,10 @@ def metarig_bilateral_measures(self):
         OPTIONAL PROPERTY
 
         a dictionary of key: value in the form Measure_Name:[side_pointA, side_pointB]
-        when processed, mean distance (excluding outliers) between the two points will be calculated and stored as the measure
+        when processed, mean distance (excluding outliers)
+        between the two points will be calculated and stored as the measure
         """
-        raise NotImplementedError(
-            f"Tracker {self.name} has not provided its measures for configuring a metarig"
-        )
+        raise NotImplementedError(f"Tracker {self.name} has not provided its measures for configuring a metarig")
 
 
 @dataclass(frozen=True, slots=True)
@@ -260,15 +252,14 @@ def frame_packet_count(self):
         return count
 
 
-@dataclass(slots=True,frozen=True)
+@dataclass(slots=True, frozen=True)
 class XYZPacket:
     sync_index: int
     point_ids: np.ndarray  # (n,1)
     point_xyz: np.ndarray  # (n,3)
-        
-    def get_point_xyz(self, point_id:int)->np.ndarray:
-        return self.point_xyz[self.point_ids==point_id]
 
-    def get_segment_ends(self, point_id_A:int, point_id_B:int)->np.ndarray:
+    def get_point_xyz(self, point_id: int) -> np.ndarray:
+        return self.point_xyz[self.point_ids == point_id]
+
+    def get_segment_ends(self, point_id_A: int, point_id_B: int) -> np.ndarray:
         return np.vstack([self.get_point_xyz(point_id_A), self.get_point_xyz(point_id_B)])
-    
\ No newline at end of file
diff --git a/caliscope/post_processing/blender_tools.py b/caliscope/post_processing/blender_tools.py
index 8ab156c0..478cb91d 100644
--- a/caliscope/post_processing/blender_tools.py
+++ b/caliscope/post_processing/blender_tools.py
@@ -1,27 +1,29 @@
-
-import caliscope.logger
 import json
-
 from pathlib import Path
-import pandas as pd
+
 import numpy as np
+import pandas as pd
 
+import caliscope.logger
 from caliscope.trackers.tracker_enum import TrackerEnum
+
 logger = caliscope.logger.get(__name__)
 
-def calculate_distance(xyz_trajectory_data:pd.DataFrame, point1:str, point2:str):
+
+def calculate_distance(xyz_trajectory_data: pd.DataFrame, point1: str, point2: str):
     """
-    Given a set of xyz trajectories from tracked and triangulated landmarks, calculate the 
+    Given a set of xyz trajectories from tracked and triangulated landmarks, calculate the
     mean distance between two named points, excluding outlier points for data cleanliness
-    
+
     """
     # calculate the distance
-    distances = np.sqrt((xyz_trajectory_data[point1 + '_x'] - xyz_trajectory_data[point2 + '_x']) ** 2 +
-                     (xyz_trajectory_data[point1 + '_y'] - xyz_trajectory_data[point2 + '_y']) ** 2 +
-                     (xyz_trajectory_data[point1 + '_z'] - xyz_trajectory_data[point2 + '_z']) ** 2)
-    
+    distances = np.sqrt(
+        (xyz_trajectory_data[point1 + "_x"] - xyz_trajectory_data[point2 + "_x"]) ** 2
+        + (xyz_trajectory_data[point1 + "_y"] - xyz_trajectory_data[point2 + "_y"]) ** 2
+        + (xyz_trajectory_data[point1 + "_z"] - xyz_trajectory_data[point2 + "_z"]) ** 2
+    )
 
-        # calculate Q1, Q3 and IQR for outlier detection
+    # calculate Q1, Q3 and IQR for outlier detection
     Q1 = distances.quantile(0.25)
     Q3 = distances.quantile(0.75)
     IQR = Q3 - Q1
@@ -34,10 +36,10 @@ def calculate_distance(xyz_trajectory_data:pd.DataFrame, point1:str, point2:str)
     return average_length
 
 
-def generate_metarig_config(tracker_enum: TrackerEnum, xyz_csv_path:Path):
+def generate_metarig_config(tracker_enum: TrackerEnum, xyz_csv_path: Path):
+    """
+    Stores metarig config json file within the tracker sub-directory within a recording folder
     """
-    Stores metarig config json file within the tracker sub-directory within a recording folder 
-    """        
     tracker = tracker_enum.value()
 
     xyz_trajectories = pd.read_csv(xyz_csv_path)
@@ -46,8 +48,8 @@ def generate_metarig_config(tracker_enum: TrackerEnum, xyz_csv_path:Path):
     # for testing purposes, need to make sure that this file is not there before proceeding
     json_path.unlink(missing_ok=True)
     assert not json_path.exists()
-    
-    autorig_config = {} # Dictionary that will become json
+
+    autorig_config = {}  # Dictionary that will become json
 
     # average distances across the bilateral measures
     for measure, points in tracker.metarig_bilateral_measures.items():
@@ -55,20 +57,19 @@ def generate_metarig_config(tracker_enum: TrackerEnum, xyz_csv_path:Path):
 
         mean_distance = 0
         for side in ["left", "right"]:
-            
             point1 = f"{side}_{points[0]}"
             point2 = f"{side}_{points[1]}"
 
-            distance = calculate_distance(xyz_trajectories, point1,point2)
-            logger.info(f"Between {point1} and {point2} the mean distance is {distance}")     
-            mean_distance += distance/2
-        autorig_config[measure] = round(mean_distance,4)
-           
-    # calculate distance across symmetrical measures       
+            distance = calculate_distance(xyz_trajectories, point1, point2)
+            logger.info(f"Between {point1} and {point2} the mean distance is {distance}")
+            mean_distance += distance / 2
+        autorig_config[measure] = round(mean_distance, 4)
+
+    # calculate distance across symmetrical measures
     for measure, points in tracker.metarig_symmetrical_measures.items():
-        distance = calculate_distance(xyz_trajectories, points[0],points[1])
-        autorig_config[measure] = round(distance,4)
-     
+        distance = calculate_distance(xyz_trajectories, points[0], points[1])
+        autorig_config[measure] = round(distance, 4)
+
     # save output to file that will be in same folder as the associated xy_csv data
-    with open(json_path,"w") as f:
-        json.dump(autorig_config, f, indent=4)    
\ No newline at end of file
+    with open(json_path, "w") as f:
+        json.dump(autorig_config, f, indent=4)
diff --git a/caliscope/post_processing/gap_filling.py b/caliscope/post_processing/gap_filling.py
index 53a108f2..8d5abd77 100644
--- a/caliscope/post_processing/gap_filling.py
+++ b/caliscope/post_processing/gap_filling.py
@@ -1,25 +1,26 @@
-import pandas as pd
 import numpy as np
+import pandas as pd
 
 import caliscope.logger
+
 logger = caliscope.logger.get(__name__)
 
 
-def gap_fill_xy(xy_base:pd.DataFrame, max_gap_size=3) -> pd.DataFrame:
+def gap_fill_xy(xy_base: pd.DataFrame, max_gap_size=3) -> pd.DataFrame:
     """
     xy_base: dataframe which should contain the following columns:
         sync_index (or frame_index)
-        frame_time	
-        port	
-        point_id	
-        img_loc_x	
-        img_loc_y	
-    
+        frame_time
+        port
+        point_id
+        img_loc_x
+        img_loc_y
+
     Note: can contain other fields that will remain in the data but will not be processed.
-    Examples: 
-        obj_loc_x	
+    Examples:
+        obj_loc_x
         obj_loc_y
-    
+
     Note that this can take one or multiple ports, though the port field must be included even if only
     1 port is being examined.
     """
@@ -33,37 +34,41 @@ def gap_fill_xy(xy_base:pd.DataFrame, max_gap_size=3) -> pd.DataFrame:
     # index_key = "frame_index"
     index_key = "sync_index"
 
-    last_port = -1 # init to impossible value to kick off log event on first run
+    last_port = -1  # init to impossible value to kick off log event on first run
 
     # Loop through each combination of port and point_id
-    for (port, point_id), group in xy_base.groupby(['port', 'point_id']):
+    for (port, point_id), group in xy_base.groupby(["port", "point_id"]):
         #### some overhead to allow sparse logging only on the first run through
         if last_port != port:
-            logger.info(f"Gap filling for (x,y) data from port {port}. Filling gaps that are {max_gap_size} frames or less...")
+            logger.info(
+                f"Gap filling for (x,y) data from port {port}. Filling gaps that are {max_gap_size} frames or less..."
+            )
         last_port = port
         ### End Conditional Logging
-        
+
         # Sort by frame_index to ensure the data is in order
         group = group.sort_values(index_key)
-    
+
         # Create a new DataFrame with all frame_index values in the range
         all_frames = pd.DataFrame({index_key: np.arange(group[index_key].min(), group[index_key].max() + 1)})
-        all_frames['port'] = port
-        all_frames['point_id'] = point_id
+        all_frames["port"] = port
+        all_frames["point_id"] = point_id
 
         # Merge the actual data with the all_frames DataFrame
-        merged = pd.merge(all_frames, group, on=['port', 'point_id', index_key], how='left')
+        merged = pd.merge(all_frames, group, on=["port", "point_id", index_key], how="left")
 
         # Calculate the size of each gap
-        merged['gap_size'] = merged['img_loc_x'].isnull().astype(int).groupby((merged['img_loc_x'].notnull()).cumsum()).cumsum()
+        merged["gap_size"] = (
+            merged["img_loc_x"].isnull().astype(int).groupby((merged["img_loc_x"].notnull()).cumsum()).cumsum()
+        )
 
         # Remove the rows where the gap is larger than GAP_SIZE_TO_FILL
-        merged = merged[merged['gap_size'] <= max_gap_size]
+        merged = merged[merged["gap_size"] <= max_gap_size]
 
         # Interpolate the values for img_loc_x and img_loc_y, limit the interpolation to GAP_SIZE_TO_FILL
-        merged['frame_time'] = merged['frame_time'].interpolate(method='linear', limit=max_gap_size).astype('float64')
-        merged['img_loc_x'] = merged['img_loc_x'].interpolate(method='linear', limit=max_gap_size).astype('float64')
-        merged['img_loc_y'] = merged['img_loc_y'].interpolate(method='linear', limit=max_gap_size).astype('float64')
+        merged["frame_time"] = merged["frame_time"].interpolate(method="linear", limit=max_gap_size).astype("float64")
+        merged["img_loc_x"] = merged["img_loc_x"].interpolate(method="linear", limit=max_gap_size).astype("float64")
+        merged["img_loc_y"] = merged["img_loc_y"].interpolate(method="linear", limit=max_gap_size).astype("float64")
 
         # Append to the overall DataFrame
         xy_filled = pd.concat([xy_filled, merged])
@@ -71,44 +76,45 @@ def gap_fill_xy(xy_base:pd.DataFrame, max_gap_size=3) -> pd.DataFrame:
     logger.info("(x,y) gap filling complete")
     return xy_filled
 
-    
 
-def gap_fill_xyz(xyz_base:pd.DataFrame, max_gap_size=3) -> pd.DataFrame:
+def gap_fill_xyz(xyz_base: pd.DataFrame, max_gap_size=3) -> pd.DataFrame:
     """
     xyz_base: dataframe which should contain the following columns:
-        sync_index 
-        point_id	
-        loc_x	
-        loc_y	
+        sync_index
+        point_id
+        loc_x
+        loc_y
         loc_z
     """
     # Initialize a DataFrame to store the data with filled gaps
     xyz_filled = pd.DataFrame()
 
     # Loop through each combination of port and point_id
-    for point_id, group in xyz_base.groupby('point_id'):
+    for point_id, group in xyz_base.groupby("point_id"):
         # Sort by frame_index to ensure the data is in order
         group = group.sort_values("sync_index")
-    
+
         # Create a new DataFrame with all frame_index values in the range
         all_frames = pd.DataFrame({"sync_index": np.arange(group["sync_index"].min(), group["sync_index"].max() + 1)})
-        all_frames['point_id'] = point_id
+        all_frames["point_id"] = point_id
 
         # Merge the actual data with the all_frames DataFrame
-        merged = pd.merge(all_frames, group, on=['point_id', "sync_index"], how='left')
+        merged = pd.merge(all_frames, group, on=["point_id", "sync_index"], how="left")
 
         # Calculate the size of each gap
-        merged['gap_size'] = merged['x_coord'].isnull().astype(int).groupby((merged['x_coord'].notnull()).cumsum()).cumsum()
+        merged["gap_size"] = (
+            merged["x_coord"].isnull().astype(int).groupby((merged["x_coord"].notnull()).cumsum()).cumsum()
+        )
 
         # Remove the rows where the gap is larger than GAP_SIZE_TO_FILL
-        merged = merged[merged['gap_size'] <= max_gap_size]
+        merged = merged[merged["gap_size"] <= max_gap_size]
 
         # Interpolate the values for img_loc_x and img_loc_y, limit the interpolation to GAP_SIZE_TO_FILL
-        merged['x_coord'] = merged['x_coord'].interpolate(method='linear', limit=max_gap_size).astype('float64')
-        merged['y_coord'] = merged['y_coord'].interpolate(method='linear', limit=max_gap_size).astype('float64')
-        merged['z_coord'] = merged['z_coord'].interpolate(method='linear', limit=max_gap_size).astype('float64')
+        merged["x_coord"] = merged["x_coord"].interpolate(method="linear", limit=max_gap_size).astype("float64")
+        merged["y_coord"] = merged["y_coord"].interpolate(method="linear", limit=max_gap_size).astype("float64")
+        merged["z_coord"] = merged["z_coord"].interpolate(method="linear", limit=max_gap_size).astype("float64")
 
         # Append to the overall DataFrame
         xyz_filled = pd.concat([xyz_filled, merged])
 
-    return xyz_filled
\ No newline at end of file
+    return xyz_filled
diff --git a/caliscope/post_processing/post_processor.py b/caliscope/post_processing/post_processor.py
index 4aa4b148..42923c99 100644
--- a/caliscope/post_processing/post_processor.py
+++ b/caliscope/post_processing/post_processor.py
@@ -1,25 +1,24 @@
-import caliscope.logger
 import shutil
-
+from pathlib import Path
 from time import sleep
 
-from pathlib import Path
 import pandas as pd
-from caliscope.triangulate.triangulation import triangulate_xy
-from caliscope.synchronized_stream_manager import SynchronizedStreamManager
 
-from caliscope.trackers.tracker_enum import TrackerEnum
+import caliscope.logger
 from caliscope.cameras.camera_array import CameraArray
-
 from caliscope.export import xyz_to_trc, xyz_to_wide_labelled
 from caliscope.post_processing.gap_filling import gap_fill_xy, gap_fill_xyz
 from caliscope.post_processing.smoothing import smooth_xyz
+from caliscope.synchronized_stream_manager import SynchronizedStreamManager
+from caliscope.trackers.tracker_enum import TrackerEnum
+from caliscope.triangulate.triangulation import triangulate_xy
 
 logger = caliscope.logger.get(__name__)
 
 # gap filling and filtering is outside the current scope of the project so I'm toggling this off for now
 APPLY_EXPERIMENTAL_POST_PROCESSING = False
 
+
 class PostProcessor:
     """
     The post processer operates independently of the session. It does not need to worry about camera management.
@@ -27,13 +26,11 @@ class PostProcessor:
     - config.toml
     - frame_time.csv
     - .mp4 files
-    
+
     The post processor will archive the active config.toml file into the subdirectory
     """
 
-    def __init__(
-        self, camera_array: CameraArray, recording_path: Path, tracker_enum: TrackerEnum
-    ):
+    def __init__(self, camera_array: CameraArray, recording_path: Path, tracker_enum: TrackerEnum):
         self.camera_array = camera_array
         self.recording_path = recording_path
         self.tracker_enum = tracker_enum
@@ -42,12 +39,10 @@ def __init__(
 
         # save out current camera array to output folder
         tracker_subdirectory = Path(self.recording_path, self.tracker_name)
-        tracker_subdirectory.mkdir(exist_ok=True,parents=True)
-        shutil.copy(Path(self.recording_path.parent.parent,"config.toml"), Path(tracker_subdirectory, "config.toml"))
-        
-        logger.info(
-            f"Creating sync stream manager for videos stored in {self.recording_path}"
-        )
+        tracker_subdirectory.mkdir(exist_ok=True, parents=True)
+        shutil.copy(Path(self.recording_path.parent.parent, "config.toml"), Path(tracker_subdirectory, "config.toml"))
+
+        logger.info(f"Creating sync stream manager for videos stored in {self.recording_path}")
         self.sync_stream_manager = SynchronizedStreamManager(
             self.recording_path, self.camera_array.cameras, self.tracker
         )
@@ -64,19 +59,11 @@ def create_xy(self, fps_target=100, include_video=True):
         while self.sync_stream_manager.recorder.recording:
             sleep(1)
             percent_complete = int(
-                (
-                    self.sync_stream_manager.recorder.sync_index
-                    / self.sync_stream_manager.mean_frame_count
-                )
-                * 100
-            )
-            logger.info(
-                f"(Stage 1 of 2): {percent_complete}% of frames processed for (x,y) landmark detection"
+                (self.sync_stream_manager.recorder.sync_index / self.sync_stream_manager.mean_frame_count) * 100
             )
+            logger.info(f"(Stage 1 of 2): {percent_complete}% of frames processed for (x,y) landmark detection")
 
-    def create_xyz(
-        self, xy_gap_fill=3, xyz_gap_fill=3, cutoff_freq=6, include_trc=True
-    ) -> None:
+    def create_xyz(self, xy_gap_fill=3, xyz_gap_fill=3, cutoff_freq=6, include_trc=True) -> None:
         """
         creates xyz_{tracker name}.csv file within the recording_path directory
 
@@ -101,32 +88,25 @@ def create_xyz(
             logger.info("Beginning data triangulation")
             xyz = triangulate_xy(xy, self.camera_array)
         else:
-            logger.warn("No points tracked. Terminating post-processing early.")
+            logger.warning("No points tracked. Terminating post-processing early.")
             return
 
         if xyz.shape[0] > 0:
             if APPLY_EXPERIMENTAL_POST_PROCESSING:
                 logger.info("Filling small gaps in (x,y,z) data")
                 xyz = gap_fill_xyz(xyz, max_gap_size=xyz_gap_fill)
-                logger.info(
-                    "Smoothing (x,y,z) using butterworth filter with cutoff frequency of 6hz"
-                )
-                xyz = smooth_xyz(
-                    xyz, order=2, fps=self.sync_stream_manager.mean_fps, cutoff=cutoff_freq
-                )
-
+                logger.info("Smoothing (x,y,z) using butterworth filter with cutoff frequency of 6hz")
+                xyz = smooth_xyz(xyz, order=2, fps=self.sync_stream_manager.mean_fps, cutoff=cutoff_freq)
 
             logger.info("Saving (x,y,z) to csv file")
             xyz_csv_path = Path(tracker_output_path, f"xyz_{self.tracker_name}.csv")
             xyz.to_csv(xyz_csv_path)
-            xyz_wide_csv_path = Path(
-                tracker_output_path, f"xyz_{self.tracker_name}_labelled.csv"
-            )
+            xyz_wide_csv_path = Path(tracker_output_path, f"xyz_{self.tracker_name}_labelled.csv")
             xyz_labelled = xyz_to_wide_labelled(xyz, self.tracker_enum.value())
             xyz_labelled.to_csv(xyz_wide_csv_path)
 
         else:
-            logger.warn("No points triangulated. Terminating post-processing early.")
+            logger.warning("No points triangulated. Terminating post-processing early.")
             return
 
         # only include trc if wanted and only if there is actually good data to export
@@ -144,9 +124,7 @@ def create_xyz(
 if __name__ == "__main__":
     from caliscope.controller import Controller
 
-    workspace_dir = Path(
-        r"C:\Users\Mac Prible\OneDrive - The University of Texas at Austin\research\caliscope\demo"
-    )
+    workspace_dir = Path(r"C:\Users\Mac Prible\OneDrive - The University of Texas at Austin\research\caliscope\demo")
     controller = Controller(workspace_dir)
     controller.load_camera_array()
 
diff --git a/caliscope/post_processing/smoothing.py b/caliscope/post_processing/smoothing.py
index 962f370e..c3f9fe7e 100644
--- a/caliscope/post_processing/smoothing.py
+++ b/caliscope/post_processing/smoothing.py
@@ -1,20 +1,16 @@
+import pandas as pd
+from scipy.signal import butter, filtfilt
 
 import caliscope.logger
 
-
-from caliscope import __root__
-import pandas as pd
-import numpy as np
-from scipy.signal import butter, filtfilt
 logger = caliscope.logger.get(__name__)
 
 
 # Define Butterworth filter functions
 def butter_lowpass(cutoff, fs, order=2):
     # cutoff frequency must be less than half the frame rate
-    if cutoff<fs/2:
-        logger.warn("Low pass filter failing due to excessively low fps / excessively high filter cutoff.")
-
+    if cutoff < fs / 2:
+        logger.warning("Low pass filter failing due to excessively low fps / excessively high filter cutoff.")
 
     nyq = 0.5 * fs  # Nyquist Frequency
     normal_cutoff = cutoff / nyq
@@ -30,50 +26,47 @@ def butter_lowpass_filter(data, cutoff, fps, order=2):
     y = filtfilt(b, a, data, padlen=padlen)
     return y
 
-def _smooth(landmark_data:pd.DataFrame, order, fps, cutoff, coord_names, index_name)->pd.DataFrame:
 
+def _smooth(landmark_data: pd.DataFrame, order, fps, cutoff, coord_names, index_name) -> pd.DataFrame:
     shifted_index_name = f"{index_name}_shifted"
 
     # get continuous groups of a given point that can be filtered
     landmark_data = landmark_data.sort_values(by=["point_id", index_name])
     landmark_data[shifted_index_name] = landmark_data[index_name].shift(1)
-    landmark_data["new_smooth_group"] = (
-        landmark_data[index_name] != landmark_data[shifted_index_name] + 1
-    )
+    landmark_data["new_smooth_group"] = landmark_data[index_name] != landmark_data[shifted_index_name] + 1
     landmark_data["smooth_group_index"] = landmark_data["new_smooth_group"].cumsum()
     landmark_data = landmark_data.drop([shifted_index_name, "new_smooth_group"], axis=1)
 
-
     # Apply the filter to each piecewise group
     logger.info("Applying butterworth filter to point coordinates")
     for coord in coord_names:
-        landmark_data[coord] = landmark_data.groupby(["smooth_group_index"])[
-            coord
-        ].transform(butter_lowpass_filter, cutoff, fps, order)
-    
+        landmark_data[coord] = landmark_data.groupby(["smooth_group_index"])[coord].transform(
+            butter_lowpass_filter, cutoff, fps, order
+        )
+
     landmark_data = landmark_data.sort_values([index_name, "point_id"])
-    
-    return landmark_data   
 
+    return landmark_data
 
 
-def _smooth_xy(xy: pd.DataFrame, order, fps, cutoff)->pd.DataFrame:
+def _smooth_xy(xy: pd.DataFrame, order, fps, cutoff) -> pd.DataFrame:
     """
-    Running this function takes a considerable amount of time. Dramatically more than 
+    Running this function takes a considerable amount of time. Dramatically more than
     the xyz version. So just let this be for now and don't bother implementing it
     in practice.
-    
+
     Gap fill the xy, but don't bother with the smoothing for now.
-    
+
     """
     # note that in future refactors, the xy coordinates my only have a frame_index and not a sync_index
-    index_name = "sync_index" 
-    coord_names = ["img_loc_x","img_loc_y"]
-    
-    return _smooth(xy, order, fps, cutoff, coord_names,index_name)
+    index_name = "sync_index"
+    coord_names = ["img_loc_x", "img_loc_y"]
 
-def smooth_xyz(xyz: pd.DataFrame, order, fps, cutoff)->pd.DataFrame:
+    return _smooth(xy, order, fps, cutoff, coord_names, index_name)
+
+
+def smooth_xyz(xyz: pd.DataFrame, order, fps, cutoff) -> pd.DataFrame:
     index_name = "sync_index"
     coord_names = ["x_coord", "y_coord", "z_coord"]
-    
-    return _smooth(xyz, order, fps, cutoff, coord_names,index_name)
\ No newline at end of file
+
+    return _smooth(xyz, order, fps, cutoff, coord_names, index_name)
diff --git a/caliscope/recording/recorded_stream.py b/caliscope/recording/recorded_stream.py
index a2a499c4..d01c6b0e 100644
--- a/caliscope/recording/recorded_stream.py
+++ b/caliscope/recording/recorded_stream.py
@@ -1,20 +1,15 @@
-
-import caliscope.logger
 import logging
-
 from pathlib import Path
 from queue import Queue
-from threading import Thread, Event
-import rtoml
+from threading import Event, Thread
+from time import perf_counter, sleep
 
 import cv2
-from time import perf_counter, sleep
-import pandas as pd
 import numpy as np
+import pandas as pd
 
+import caliscope.logger
 from caliscope.packets import FramePacket, Tracker
-from caliscope.cameras.camera_array import CameraData
-from caliscope.configurator import Configurator
 
 logger = caliscope.logger.get(__name__)
 logger.setLevel(logging.INFO)
@@ -41,7 +36,10 @@ def __init__(
         self.directory = directory
         self.port = port
         self.rotation_count = rotation_count
-        self.break_on_last = break_on_last  # stop while loop if end reached. Preferred behavior for automated file processing, not interactive frame selection
+
+        # stop while loop if end reached.
+        # Preferred behavior for automated file processing, not interactive frame selection
+        self.break_on_last = break_on_last
 
         self.tracker = tracker
 
@@ -53,9 +51,9 @@ def __init__(
         if fps_target is None:
             fps_target = self.original_fps
 
-        width =  int(self.capture.get(cv2.CAP_PROP_FRAME_WIDTH))
+        width = int(self.capture.get(cv2.CAP_PROP_FRAME_WIDTH))
         height = int(self.capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
-        self.size = (width,height)
+        self.size = (width, height)
 
         self.stop_event = Event()
         self._jump_q = Queue(maxsize=1)
@@ -69,13 +67,9 @@ def __init__(
         if synched_frames_history_path.exists():
             synched_frames_history = pd.read_csv(synched_frames_history_path)
 
-            self.port_history = synched_frames_history[
-                synched_frames_history["port"] == self.port
-            ]
+            self.port_history = synched_frames_history[synched_frames_history["port"] == self.port]
 
-            self.port_history["frame_index"] = (
-                self.port_history["frame_time"].rank(method="min").astype(int) - 1
-            )
+            self.port_history["frame_index"] = self.port_history["frame_time"].rank(method="min").astype(int) - 1
 
         ########### INFER TIME STAMP IF NOT AVAILABLE ####################################
         else:
@@ -86,7 +80,8 @@ def __init__(
             }
             self.port_history = pd.DataFrame(mocked_port_history)
 
-        # note that this is not simply 0 and frame count because the syncronized recording might start recording many frames into pulling from a camera
+        # note that this is not simply 0 and frame count because the syncronized recording might start recording many
+        # frames into pulling from a camera
         # this is one of those unhappy artifacts that may be a good candidate for simplification in a future refactor
         self.start_frame_index = self.port_history["frame_index"].min()
         self.last_frame_index = self.port_history["frame_index"].max()
@@ -99,7 +94,7 @@ def __init__(
     # def set_tracking_on(self, track: bool):
     #     if track:
     #         logger.info(f"Turning tracking on for recorded stream {self.port}")
-    #         self.track_points = 
+    #         self.track_points =
     #     else:
     #         logger.info(f"Turning tracking off for recorded stream {self.port}")
     #         self.track_points.clear()
@@ -110,21 +105,15 @@ def subscribe(self, queue: Queue):
             self.subscribers.append(queue)
             logger.info(f"...now {len(self.subscribers)} subscriber(s) at {self.port}")
         else:
-            logger.warn(
-                f"Attempted to subscribe to recorded stream at port {self.port} twice"
-            )
+            logger.warning(f"Attempted to subscribe to recorded stream at port {self.port} twice")
 
     def unsubscribe(self, queue: Queue):
         if queue in self.subscribers:
-            logger.info(
-                f"Removing subscriber from queue at recorded stream {self.port}"
-            )
+            logger.info(f"Removing subscriber from queue at recorded stream {self.port}")
             self.subscribers.remove(queue)
-            logger.info(
-                f"{len(self.subscribers)} subscriber(s) remain at recorded stream {self.port}"
-            )
+            logger.info(f"{len(self.subscribers)} subscriber(s) remain at recorded stream {self.port}")
         else:
-            logger.warn(
+            logger.warning(
                 f"Attempted to unsubscribe to recorded stream that was not subscribed to\
                 at port {self.port} twice"
             )
@@ -199,19 +188,14 @@ def _play_worker(self):
 
             if self.milestones is not None:
                 sleep(self.wait_to_next_frame())
-            logger.debug(
-                f"about to read frame {self.frame_index} from capture at port {self.port}"
-            )
+            logger.info(f"about to read frame {self.frame_index} from capture at port {self.port}")
             success, self.frame = self.capture.read()
 
             if not success:
                 break
 
-
             if self.tracker is not None:
-                self.point_data = self.tracker.get_points(
-                    self.frame, self.port, self.rotation_count
-                )
+                self.point_data = self.tracker.get_points(self.frame, self.port, self.rotation_count)
                 draw_instructions = self.tracker.scatter_draw_instructions
             else:
                 self.point_data = None
@@ -233,7 +217,7 @@ def _play_worker(self):
             for q in self.subscribers:
                 q.put(frame_packet)
 
-            # self.out_q.put(frame_packet)
+            logger.debug(f"Incrementing frame index from {self.frame_index} to {self.frame_index+1}")
             self.frame_index += 1
 
             if self.frame_index > self.last_frame_index and self.break_on_last:
@@ -269,12 +253,8 @@ def _play_worker(self):
                     break
 
                 sleep(0.1)
-
-            ############
+            #######################################################
             if not self._jump_q.empty():
                 self.frame_index = self._jump_q.get()
-                logger.info(
-                    f"Setting port {self.port} capture object to frame index {self.frame_index}"
-                )
+                logger.info(f"Setting port {self.port} capture object to frame index {self.frame_index}")
                 self.capture.set(cv2.CAP_PROP_POS_FRAMES, self.frame_index)
-
diff --git a/caliscope/recording/video_recorder.py b/caliscope/recording/video_recorder.py
index f27111a4..6e3cb053 100644
--- a/caliscope/recording/video_recorder.py
+++ b/caliscope/recording/video_recorder.py
@@ -1,13 +1,14 @@
 # from PySide6.QtCore import QObject, Signal
 from pathlib import Path
 from queue import Queue
-from threading import Thread, Event
+from threading import Event, Thread
+
 import cv2
 import pandas as pd
 
+import caliscope.logger
 from caliscope.cameras.synchronizer import Synchronizer
 from caliscope.packets import SyncPacket
-import caliscope.logger
 
 logger = caliscope.logger.get(__name__)
 
@@ -47,15 +48,11 @@ def build_video_writers(self):
             logger.info(f"Building video writer for port {port}; recording to {path}")
             fourcc = cv2.VideoWriter_fourcc(*"MP4V")
             frame_size = stream.size
-            logger.info(
-                f"Creating video writer with fps of {stream.original_fps} and frame size of {frame_size}"
-            )
+            logger.info(f"Creating video writer with fps of {stream.original_fps} and frame size of {frame_size}")
             writer = cv2.VideoWriter(path, fourcc, stream.original_fps, frame_size)
             self.video_writers[port] = writer
 
-    def save_data_worker(
-        self, include_video: bool, show_points: bool, store_point_history: bool
-    ):
+    def save_data_worker(self, include_video: bool, show_points: bool, store_point_history: bool):
         # connect video recorder to synchronizer via an "in" queue
         if include_video:
             self.build_video_writers()
@@ -92,9 +89,7 @@ def save_data_worker(
             logger.debug("Getting size of sync packet q")
             backlog = self.sync_packet_in_q.qsize()
             if backlog % 25 == 0 and backlog != 0:
-                logger.info(
-                    f"Size of unsaved frames on the recording queue is {self.sync_packet_in_q.qsize()}"
-                )
+                logger.info(f"Size of unsaved frames on the recording queue is {self.sync_packet_in_q.qsize()}")
 
             if sync_packet is None:
                 # relenvant when
@@ -118,9 +113,7 @@ def save_data_worker(
                     if include_video:
                         # store the frame
                         if self.sync_index % 50 == 0:
-                            logger.debug(
-                                f"Writing frame for port {port} and sync index {self.sync_index}"
-                            )
+                            logger.debug(f"Writing frame for port {port} and sync index {self.sync_index}")
                             logger.debug(f"frame size  {frame.shape}")
 
                         self.video_writers[port].write(frame)
@@ -199,19 +192,6 @@ def start_recording(
         self.destination_folder = destination_folder
         # create the folder if it doesn't already exist
         self.destination_folder.mkdir(exist_ok=True, parents=True)
-
-        # # Because calibration files are nested in a calibration directory, need to go
-        # # to parent.parent to get the config.toml file
-        # if self.destination_folder.parent.stem == "calibration":
-        #     source_config_path = Path(self.destination_folder.parent.parent, "config.toml")
-        # else:   # just a regular recording
-        #     source_config_path = Path(self.destination_folder.parent, "config.toml")
-
-        # No longer storing config file with recordings....can't know when they were done relative to calibration so will only complicate things..
-        # source_config_path = find_config_file(self.destination_folder)
-        # duplicate_config_path = Path(self.destination_folder,"config.toml")
-        # shutil.copy2(source_config_path,duplicate_config_path)
-
         self.recording = True
         self.recording_thread = Thread(
             target=self.save_data_worker,
diff --git a/caliscope/synchronized_stream_manager.py b/caliscope/synchronized_stream_manager.py
index 37797d57..fca513e6 100644
--- a/caliscope/synchronized_stream_manager.py
+++ b/caliscope/synchronized_stream_manager.py
@@ -1,11 +1,13 @@
-import caliscope.logger
 import statistics
-import cv2
 from pathlib import Path
-from caliscope.cameras.synchronizer import Synchronizer
-from caliscope.recording.recorded_stream import RecordedStream
+
+import cv2
+
+import caliscope.logger
 from caliscope.cameras.camera_array import CameraData
+from caliscope.cameras.synchronizer import Synchronizer
 from caliscope.packets import Tracker
+from caliscope.recording.recorded_stream import RecordedStream
 from caliscope.recording.video_recorder import VideoRecorder
 
 logger = caliscope.logger.get(__name__)
@@ -78,17 +80,16 @@ def process_streams(self, fps_target=None, include_video=True):
 
         if fps_target is None:
             fps_target = self.mean_fps
-        
+
         logger.info(f"About to start playing video streams to be processed. Streams: {self.streams}")
         for port, stream in self.streams.items():
-
             if fps_target is not None:
                 stream.set_fps_target(fps_target)
 
             stream.play_video()
-            
+
     def load_video_properties(self):
-        fps   = []
+        fps = []
         frame_count = []
         logger.info(f"About to load video properties for files stored in {self.recording_dir}")
         logger.info(f"Current camera data is: {self.all_camera_data}")
@@ -102,8 +103,8 @@ def load_video_properties(self):
 
         self.mean_fps = statistics.mean(fps)
         self.mean_frame_count = statistics.mean(frame_count)
-        
-        
+
+
 def read_video_properties(source_path: Path) -> dict:
     # Dictionary to hold video properties
     properties = {}
@@ -126,4 +127,4 @@ def read_video_properties(source_path: Path) -> dict:
     # Release the video capture object
     video.release()
 
-    return properties
\ No newline at end of file
+    return properties
diff --git a/caliscope/tracker.py b/caliscope/tracker.py
index 47b0ffff..1b6a3c34 100644
--- a/caliscope/tracker.py
+++ b/caliscope/tracker.py
@@ -1,9 +1,11 @@
+from abc import ABC, abstractmethod
 from dataclasses import dataclass
+
 import numpy as np
-from abc import ABC, abstractmethod
-from caliscope.packets import PointPacket, XYZPacket
-from pyqtgraph.opengl import GLLinePlotItem
 import pyqtgraph as pg
+from pyqtgraph.opengl import GLLinePlotItem
+
+from caliscope.packets import PointPacket, XYZPacket
 
 
 class Tracker(ABC):
@@ -17,9 +19,7 @@ def name(self) -> str:
         pass
 
     @abstractmethod
-    def get_points(
-        self, frame: np.ndarray, port: int, rotation_count: int
-    ) -> PointPacket:
+    def get_points(self, frame: np.ndarray, port: int, rotation_count: int) -> PointPacket:
         """
         frame: np.ndarray from reading an OpenCV capture object
 
@@ -85,9 +85,7 @@ def metarig_symmetrical_measures(self):
         left_pointA,left_pointB and right_pointA, right_pointB will be calculated.
         The mean of the two sides will be taken
         """
-        raise NotImplementedError(
-            f"Tracker {self.name} has not provided its measures for configuring a metarig"
-        )
+        raise NotImplementedError(f"Tracker {self.name} has not provided its measures for configuring a metarig")
 
     @property
     def metarig_bilateral_measures(self):
@@ -95,11 +93,10 @@ def metarig_bilateral_measures(self):
         OPTIONAL PROPERTY
 
         a dictionary of key: value in the form Measure_Name:[side_pointA, side_pointB]
-        when processed, mean distance (excluding outliers) between the two points will be calculated and stored as the measure
+        when processed, mean distance (excluding outliers) between the two points
+        will be calculated and stored as the measure
         """
-        raise NotImplementedError(
-            f"Tracker {self.name} has not provided its measures for configuring a metarig"
-        )
+        raise NotImplementedError(f"Tracker {self.name} has not provided its measures for configuring a metarig")
 
 
 @dataclass(slots=True, frozen=True)
@@ -123,10 +120,10 @@ def __post_init__(self):
                 color=pg.mkColor(segment.color), width=segment.width, mode="lines"
             )
 
-        self.point_ids = {value:key for key,value in self.point_names.items()}
+        self.point_ids = {value: key for key, value in self.point_names.items()}
+
     def set_points(self, xyz_packet: XYZPacket):
         for segment in self.segments:
             A_id = self.point_ids[segment.point_A]
             B_id = self.point_ids[segment.point_B]
-            self.line_plots[segment.name].setData(
-                pos=xyz_packet.get_segment_ends(A_id,B_id))
+            self.line_plots[segment.name].setData(pos=xyz_packet.get_segment_ends(A_id, B_id))
diff --git a/caliscope/trackers/charuco_tracker.py b/caliscope/trackers/charuco_tracker.py
index 94fd6853..b70543f7 100644
--- a/caliscope/trackers/charuco_tracker.py
+++ b/caliscope/trackers/charuco_tracker.py
@@ -2,19 +2,19 @@
 # detector and the corner drawer...like, there will need to be something that
 # accumulates a frame of corners to be drawn onto the displayed frame.
 
-import caliscope.logger
 import cv2
 import numpy as np
+
 import caliscope.calibration.draw_charuco
-from caliscope.calibration.charuco import Charuco
+import caliscope.logger
 from caliscope.packets import PointPacket
 from caliscope.tracker import Tracker
 
 logger = caliscope.logger.get(__name__)
 
+
 class CharucoTracker(Tracker):
     def __init__(self, charuco):
-
         # need camera to know resolution and to assign calibration parameters
         # to camera
         self.charuco = charuco
@@ -29,8 +29,8 @@ def __init__(self, charuco):
     def name(self):
         return "CHARUCO"
 
-    def get_points(self, frame:np.ndarray, port:int, rotation_count:int)->PointPacket:
-        """Will check for charuco corners in the frame, if it doesn't find any, 
+    def get_points(self, frame: np.ndarray, port: int, rotation_count: int) -> PointPacket:
+        """Will check for charuco corners in the frame, if it doesn't find any,
         then it will look for corners in the mirror image of the frame"""
 
         # invert the frame for detection if needed
@@ -43,36 +43,35 @@ def get_points(self, frame:np.ndarray, port:int, rotation_count:int)->PointPacke
         if not ids.any():
             gray = cv2.flip(gray, 1)
             ids, img_loc = self.find_corners_single_frame(gray, mirror=True)
-        
-        obj_loc = self.get_obj_loc(ids) 
+
+        obj_loc = self.get_obj_loc(ids)
         point_packet = PointPacket(ids, img_loc, obj_loc)
-        
+
         return point_packet
-    
-    def get_point_name(self, point_id:int) -> str:
+
+    def get_point_name(self, point_id: int) -> str:
         return str(point_id)
 
-    def get_point_id(self, point_name:str) -> int:
+    def get_point_id(self, point_name: str) -> int:
         return int(point_name)
 
     def get_connected_points(self):
         return self.charuco.get_connected_points()
 
-    def find_corners_single_frame(self,gray_frame, mirror):
-
+    def find_corners_single_frame(self, gray_frame, mirror):
         ids = np.array([])
         img_loc = np.array([])
 
         # detect if aruco markers are present
-        aruco_corners, aruco_ids, rejected = cv2.aruco.detectMarkers(
-            gray_frame, self.dictionary_object
-        )
+        aruco_corners, aruco_ids, rejected = cv2.aruco.detectMarkers(gray_frame, self.dictionary_object)
 
         # if so, then interpolate to the Charuco Corners and return what you found
-        if len(aruco_corners) >3:
-            (success, _img_loc, _ids,) = cv2.aruco.interpolateCornersCharuco(
-                aruco_corners, aruco_ids, gray_frame, self.board
-            )
+        if len(aruco_corners) > 3:
+            (
+                success,
+                _img_loc,
+                _ids,
+            ) = cv2.aruco.interpolateCornersCharuco(aruco_corners, aruco_ids, gray_frame, self.board)
 
             # This occasionally errors out...
             # only offers possible refinement so if it fails, just move along
@@ -84,35 +83,31 @@ def find_corners_single_frame(self,gray_frame, mirror):
                     (-1, -1),
                     self.criteria,
                 )
-            except:
-                logger.debug("Sub pixel detection failed")
+            except Exception as e:
+                logger.debug(f"Sub pixel detection failed: {e}")
 
             if success:
                 # assign to tracker
-                ids = _ids[:,0]
-                img_loc = _img_loc[:,0]
+                ids = _ids[:, 0]
+                img_loc = _img_loc[:, 0]
 
                 # flip coordinates if mirrored image fed in
                 frame_width = gray_frame.shape[1]  # used for flipping mirrored corners back
                 if mirror:
                     img_loc[:, 0] = frame_width - img_loc[:, 0]
-                
 
-                
         return ids, img_loc
 
-    def get_obj_loc(self, ids:np.ndarray):
+    def get_obj_loc(self, ids: np.ndarray):
         """Objective position of charuco corners in a board frame of reference"""
         # if self.ids == np.array([0]):
-            # print("wait")
+        # print("wait")
         if len(ids) > 0:
             return self.board.getChessboardCorners()[ids, :]
         else:
             return np.array([])
 
     # @property
-    def scatter_draw_instructions(self, point_id: int) ->dict:
-        rules = {"radius":5,
-                 "color":(0,0,220),
-                 "thickness":3}
-        return rules
\ No newline at end of file
+    def scatter_draw_instructions(self, point_id: int) -> dict:
+        rules = {"radius": 5, "color": (0, 0, 220), "thickness": 3}
+        return rules
diff --git a/caliscope/trackers/face_tracker.py b/caliscope/trackers/face_tracker.py
index f8d68c3e..9d19d642 100644
--- a/caliscope/trackers/face_tracker.py
+++ b/caliscope/trackers/face_tracker.py
@@ -1,18 +1,20 @@
-import caliscope.logger
-
-from threading import Thread
 from queue import Queue
+from threading import Thread
 
+import cv2
 import mediapipe as mp
 import numpy as np
-import cv2
+
+import caliscope.logger
 
 # cap = cv2.VideoCapture(0)
 from caliscope.packets import PointPacket
 from caliscope.tracker import Tracker
 from caliscope.trackers.helper import apply_rotation, unrotate_points
+
 logger = caliscope.logger.get(__name__)
 
+
 class FaceTracker(Tracker):
     # Initialize MediaPipe Facemeshes and Drawing utility
     def __init__(self) -> None:
@@ -20,12 +22,11 @@ def __init__(self) -> None:
         self.out_queue = Queue(-1)
 
         # each port gets its own mediapipe context manager
-        # use a dictionary of queues for passing 
+        # use a dictionary of queues for passing
         self.in_queues = {}
         self.out_queues = {}
         self.threads = {}
 
-
     @property
     def name(self):
         return "FACE"
@@ -33,10 +34,7 @@ def name(self):
     def run_frame_processor(self, port: int, rotation_count: int):
         # Create a MediaPipe FaceMesh instance
         with mp.solutions.face_mesh.FaceMesh(
-            static_image_mode=False,
-            max_num_faces=1,
-            refine_landmarks=True,
-            min_detection_confidence=0.5
+            static_image_mode=False, max_num_faces=1, refine_landmarks=True, min_detection_confidence=0.5
         ) as facemeshes:
             while True:
                 frame = self.in_queues[port].get()
@@ -63,16 +61,13 @@ def run_frame_processor(self, port: int, rotation_count: int):
 
                 point_ids = np.array(point_ids)
                 landmark_xy = np.array(landmark_xy)
-                landmark_xy = unrotate_points(landmark_xy, rotation_count, width,height)
+                landmark_xy = unrotate_points(landmark_xy, rotation_count, width, height)
 
                 point_packet = PointPacket(point_ids, landmark_xy)
 
                 self.out_queues[port].put(point_packet)
 
-
-    def get_points(
-        self, frame: np.ndarray, port: int, rotation_count: int
-    ) -> PointPacket:
+    def get_points(self, frame: np.ndarray, port: int, rotation_count: int) -> PointPacket:
         if port not in self.in_queues.keys():
             self.in_queues[port] = Queue(1)
             self.out_queues[port] = Queue(1)
@@ -84,7 +79,6 @@ def get_points(
             )
             self.threads[port].start()
 
-
         self.in_queues[port].put(frame)
         point_packet = self.out_queues[port].get()
 
@@ -94,39 +88,96 @@ def get_point_name(self, point_id: int) -> str:
         return str(point_id)
 
     def scatter_draw_instructions(self, point_id: int) -> dict:
-        if POINT_ID2NAME[point_id] == 'silhouette':
+        if POINT_ID2NAME[point_id] == "silhouette":
             rules = {"radius": 5, "color": (0, 0, 0), "thickness": 3}
-        if POINT_ID2NAME[point_id] in ('lipsUpperOuter', 'lipsLowerOuter', 'lipsUpperInner', 'lipsLowerInner'):
+        if POINT_ID2NAME[point_id] in ("lipsUpperOuter", "lipsLowerOuter", "lipsUpperInner", "lipsLowerInner"):
             rules = {"radius": 5, "color": (128, 0, 0), "thickness": 3}
-        if POINT_ID2NAME[point_id] in ('rightEyeUpper0', 'rightEyeLower0', 'rightEyeUpper1', 'rightEyeLower1', 'rightEyeUpper2', 'rightEyeLower2', 'rightEyeLower3', 'rightEyeIris'):
+        if POINT_ID2NAME[point_id] in (
+            "rightEyeUpper0",
+            "rightEyeLower0",
+            "rightEyeUpper1",
+            "rightEyeLower1",
+            "rightEyeUpper2",
+            "rightEyeLower2",
+            "rightEyeLower3",
+            "rightEyeIris",
+        ):
             rules = {"radius": 5, "color": (0, 255, 0), "thickness": 3}
-        if POINT_ID2NAME[point_id] in ('rightEyebrowUpper', 'rightEyebrowLower'):
+        if POINT_ID2NAME[point_id] in ("rightEyebrowUpper", "rightEyebrowLower"):
             rules = {"radius": 5, "color": (0, 128, 0), "thickness": 3}
-        if POINT_ID2NAME[point_id] in ('leftEyeUpper0', 'leftEyeLower0', 'leftEyeUpper1', 'leftEyeLower1', 'leftEyeUpper2', 'leftEyeLower2', 'leftEyeLower3', 'leftEyeIris'):
+        if POINT_ID2NAME[point_id] in (
+            "leftEyeUpper0",
+            "leftEyeLower0",
+            "leftEyeUpper1",
+            "leftEyeLower1",
+            "leftEyeUpper2",
+            "leftEyeLower2",
+            "leftEyeLower3",
+            "leftEyeIris",
+        ):
             rules = {"radius": 5, "color": (255, 0, 0), "thickness": 3}
-        if POINT_ID2NAME[point_id] in ('leftEyebrowUpper', 'leftEyebrowLower'):
+        if POINT_ID2NAME[point_id] in ("leftEyebrowUpper", "leftEyebrowLower"):
             rules = {"radius": 5, "color": (128, 0, 0), "thickness": 3}
-        if POINT_ID2NAME[point_id] == 'midwayBetweenEyes':
+        if POINT_ID2NAME[point_id] == "midwayBetweenEyes":
             rules = {"radius": 5, "color": (0, 0, 0), "thickness": 3}
-        if POINT_ID2NAME[point_id] == ('noseTip', 'noseBottom', 'noseRightCorner', 'noseLeftCorner', 'leftCheek', 'rightCheek'):
+        if POINT_ID2NAME[point_id] == (
+            "noseTip",
+            "noseBottom",
+            "noseRightCorner",
+            "noseLeftCorner",
+            "leftCheek",
+            "rightCheek",
+        ):
             rules = {"radius": 5, "color": (0, 0, 255), "thickness": 3}
         else:
             rules = {"radius": 5, "color": (0, 0, 0), "thickness": 3}
         return rules
 
+
 # Keypoint names copied from tfjs under Apache License 2.0, "AS-IS".
 NAME2KEYPOINTS = {
     "silhouette": [
-        10,  338, 297, 332, 284, 251, 389, 356, 454, 323, 361, 288,
-        397, 365, 379, 378, 400, 377, 152, 148, 176, 149, 150, 136,
-        172, 58,  132, 93,  234, 127, 162, 21,  54,  103, 67,  109
+        10,
+        338,
+        297,
+        332,
+        284,
+        251,
+        389,
+        356,
+        454,
+        323,
+        361,
+        288,
+        397,
+        365,
+        379,
+        378,
+        400,
+        377,
+        152,
+        148,
+        176,
+        149,
+        150,
+        136,
+        172,
+        58,
+        132,
+        93,
+        234,
+        127,
+        162,
+        21,
+        54,
+        103,
+        67,
+        109,
     ],
-
     "lipsUpperOuter": [61, 185, 40, 39, 37, 0, 267, 269, 270, 409, 291],
     "lipsLowerOuter": [146, 91, 181, 84, 17, 314, 405, 321, 375, 291],
     "lipsUpperInner": [78, 191, 80, 81, 82, 13, 312, 311, 310, 415, 308],
     "lipsLowerInner": [78, 95, 88, 178, 87, 14, 317, 402, 318, 324, 308],
-
     "rightEyeUpper0": [246, 161, 160, 159, 158, 157, 173],
     "rightEyeLower0": [33, 7, 163, 144, 145, 153, 154, 155, 133],
     "rightEyeUpper1": [247, 30, 29, 27, 28, 56, 190],
@@ -134,12 +185,9 @@ def scatter_draw_instructions(self, point_id: int) -> dict:
     "rightEyeUpper2": [113, 225, 224, 223, 222, 221, 189],
     "rightEyeLower2": [226, 31, 228, 229, 230, 231, 232, 233, 244],
     "rightEyeLower3": [143, 111, 117, 118, 119, 120, 121, 128, 245],
-
     "rightEyebrowUpper": [156, 70, 63, 105, 66, 107, 55, 193],
     "rightEyebrowLower": [35, 124, 46, 53, 52, 65],
-
     "rightEyeIris": [473, 474, 475, 476, 477],
-
     "leftEyeUpper0": [466, 388, 387, 386, 385, 384, 398],
     "leftEyeLower0": [263, 249, 390, 373, 374, 380, 381, 382, 362],
     "leftEyeUpper1": [467, 260, 259, 257, 258, 286, 414],
@@ -147,21 +195,16 @@ def scatter_draw_instructions(self, point_id: int) -> dict:
     "leftEyeUpper2": [342, 445, 444, 443, 442, 441, 413],
     "leftEyeLower2": [446, 261, 448, 449, 450, 451, 452, 453, 464],
     "leftEyeLower3": [372, 340, 346, 347, 348, 349, 350, 357, 465],
-
     "leftEyebrowUpper": [383, 300, 293, 334, 296, 336, 285, 417],
     "leftEyebrowLower": [265, 353, 276, 283, 282, 295],
-
     "leftEyeIris": [468, 469, 470, 471, 472],
-
     "midwayBetweenEyes": [168],
-
     "noseTip": [1],
     "noseBottom": [2],
     "noseRightCorner": [98],
     "noseLeftCorner": [327],
-
     "rightCheek": [205],
-    "leftCheek": [425]
+    "leftCheek": [425],
 }
 
 NAMES = sorted(NAME2KEYPOINTS)
diff --git a/caliscope/trackers/hand_tracker.py b/caliscope/trackers/hand_tracker.py
index 39b3a6c4..be032c92 100644
--- a/caliscope/trackers/hand_tracker.py
+++ b/caliscope/trackers/hand_tracker.py
@@ -1,18 +1,20 @@
-import caliscope.logger
-
-from threading import Thread
 from queue import Queue
+from threading import Thread
 
+import cv2
 import mediapipe as mp
 import numpy as np
-import cv2
+
+import caliscope.logger
 
 # cap = cv2.VideoCapture(0)
 from caliscope.packets import PointPacket
 from caliscope.tracker import Tracker
 from caliscope.trackers.helper import apply_rotation, unrotate_points
+
 logger = caliscope.logger.get(__name__)
 
+
 class HandTracker(Tracker):
     # Initialize MediaPipe Hands and Drawing utility
     def __init__(self) -> None:
@@ -20,12 +22,11 @@ def __init__(self) -> None:
         self.out_queue = Queue(-1)
 
         # each port gets its own mediapipe context manager
-        # use a dictionary of queues for passing 
+        # use a dictionary of queues for passing
         self.in_queues = {}
         self.out_queues = {}
         self.threads = {}
 
-
     @property
     def name(self):
         return "HAND"
@@ -80,16 +81,13 @@ def run_frame_processor(self, port: int, rotation_count: int):
 
                 point_ids = np.array(point_ids)
                 landmark_xy = np.array(landmark_xy)
-                landmark_xy = unrotate_points(landmark_xy, rotation_count, width,height)
+                landmark_xy = unrotate_points(landmark_xy, rotation_count, width, height)
 
                 point_packet = PointPacket(point_ids, landmark_xy)
 
                 self.out_queues[port].put(point_packet)
 
-
-    def get_points(
-        self, frame: np.ndarray, port: int, rotation_count: int
-    ) -> PointPacket:
+    def get_points(self, frame: np.ndarray, port: int, rotation_count: int) -> PointPacket:
         if port not in self.in_queues.keys():
             self.in_queues[port] = Queue(1)
             self.out_queues[port] = Queue(1)
@@ -101,7 +99,6 @@ def get_points(
             )
             self.threads[port].start()
 
-
         self.in_queues[port].put(frame)
         point_packet = self.out_queues[port].get()
 
@@ -116,4 +113,3 @@ def scatter_draw_instructions(self, point_id: int) -> dict:
         else:
             rules = {"radius": 5, "color": (220, 0, 0), "thickness": 3}
         return rules
-
diff --git a/caliscope/trackers/helper.py b/caliscope/trackers/helper.py
index 515911fe..090229d3 100644
--- a/caliscope/trackers/helper.py
+++ b/caliscope/trackers/helper.py
@@ -1,6 +1,7 @@
 import cv2
 import numpy as np
 
+
 def apply_rotation(frame: np.ndarray, rotation_count: int) -> np.ndarray:
     if rotation_count == 0:
         pass
@@ -14,12 +15,10 @@ def apply_rotation(frame: np.ndarray, rotation_count: int) -> np.ndarray:
     return frame
 
 
-def unrotate_points(
-    xy: np.ndarray, rotation_count: int, frame_width: int, frame_height: int
-) -> np.ndarray:
+def unrotate_points(xy: np.ndarray, rotation_count: int, frame_width: int, frame_height: int) -> np.ndarray:
     xy_unrotated = xy.copy()
 
-    if rotation_count == 0 or len(xy) ==0:
+    if rotation_count == 0 or len(xy) == 0:
         pass
     elif rotation_count in [1, -3]:
         # Reverse of 90 degrees clockwise rotation
diff --git a/caliscope/trackers/holistic/holistic_tracker.py b/caliscope/trackers/holistic/holistic_tracker.py
index 630bcb8a..89b82c0a 100644
--- a/caliscope/trackers/holistic/holistic_tracker.py
+++ b/caliscope/trackers/holistic/holistic_tracker.py
@@ -1,19 +1,19 @@
-
-from threading import Thread
-from queue import Queue
 from pathlib import Path
+from queue import Queue
+from threading import Thread
 
+import cv2
 import mediapipe as mp
 import numpy as np
-import cv2
+
+import caliscope.logger
 
 # cap = cv2.VideoCapture(0)
 from caliscope.packets import PointPacket
-from caliscope.tracker import Tracker, WireFrameView, Segment
+from caliscope.tracker import Tracker
 from caliscope.trackers.helper import apply_rotation, unrotate_points
 from caliscope.trackers.wireframe_builder import get_wireframe
 
-import caliscope.logger
 logger = caliscope.logger.get(__name__)
 
 DRAW_IGNORE_LIST = [
@@ -132,7 +132,7 @@ def __init__(self) -> None:
         self.in_queues = {}
         self.out_queues = {}
         self.threads = {}
-        wireframe_spec_path = Path(Path(__file__).parent,"holistic_wireframe.toml")
+        wireframe_spec_path = Path(Path(__file__).parent, "holistic_wireframe.toml")
         self.wireframe = get_wireframe(wireframe_spec_path, POINT_NAMES)
 
     @property
@@ -141,9 +141,7 @@ def name(self):
 
     def run_frame_processor(self, port: int, rotation_count: int):
         # Create a MediaPipe pose instance
-        with mp.solutions.holistic.Holistic(
-            min_detection_confidence=0.8, min_tracking_confidence=0.8
-        ) as holistic:
+        with mp.solutions.holistic.Holistic(min_detection_confidence=0.8, min_tracking_confidence=0.8) as holistic:
             while True:
                 frame = self.in_queues[port].get()
                 # apply rotation as needed
@@ -159,17 +157,10 @@ def run_frame_processor(self, port: int, rotation_count: int):
                 landmark_xy = []
 
                 if results.pose_landmarks:
-                    for landmark_id, landmark in enumerate(
-                        results.pose_landmarks.landmark
-                    ):
+                    for landmark_id, landmark in enumerate(results.pose_landmarks.landmark):
                         # mediapipe expresses in terms of percent of frame, so must map to pixel position
                         x, y = int(landmark.x * width), int(landmark.y * height)
-                        if (
-                            landmark.x < 0
-                            or landmark.x > 1
-                            or landmark.y < 0
-                            or landmark.y > 1
-                        ):
+                        if landmark.x < 0 or landmark.x > 1 or landmark.y < 0 or landmark.y > 1:
                             # ignore
                             pass
                         else:
@@ -177,17 +168,10 @@ def run_frame_processor(self, port: int, rotation_count: int):
                             landmark_xy.append((x, y))
 
                 if results.right_hand_landmarks:
-                    for landmark_id, landmark in enumerate(
-                        results.right_hand_landmarks.landmark
-                    ):
+                    for landmark_id, landmark in enumerate(results.right_hand_landmarks.landmark):
                         # mediapipe expresses in terms of percent of frame, so must map to pixel position
                         x, y = int(landmark.x * width), int(landmark.y * height)
-                        if (
-                            landmark.x < 0
-                            or landmark.x > 1
-                            or landmark.y < 0
-                            or landmark.y > 1
-                        ):
+                        if landmark.x < 0 or landmark.x > 1 or landmark.y < 0 or landmark.y > 1:
                             # ignore
                             pass
                         else:
@@ -195,17 +179,10 @@ def run_frame_processor(self, port: int, rotation_count: int):
                             landmark_xy.append((x, y))
 
                 if results.left_hand_landmarks:
-                    for landmark_id, landmark in enumerate(
-                        results.left_hand_landmarks.landmark
-                    ):
+                    for landmark_id, landmark in enumerate(results.left_hand_landmarks.landmark):
                         # mediapipe expresses in terms of percent of frame, so must map to pixel positionND_OFFSET
                         x, y = int(landmark.x * width), int(landmark.y * height)
-                        if (
-                            landmark.x < 0
-                            or landmark.x > 1
-                            or landmark.y < 0
-                            or landmark.y > 1
-                        ):
+                        if landmark.x < 0 or landmark.x > 1 or landmark.y < 0 or landmark.y > 1:
                             # ignore
                             pass
                         else:
@@ -213,17 +190,10 @@ def run_frame_processor(self, port: int, rotation_count: int):
                             landmark_xy.append((x, y))
 
                 if results.face_landmarks:
-                    for landmark_id, landmark in enumerate(
-                        results.face_landmarks.landmark
-                    ):
+                    for landmark_id, landmark in enumerate(results.face_landmarks.landmark):
                         # mediapipe expresses in terms of percent of frame, so must map to pixel positionFSET
                         x, y = int(landmark.x * width), int(landmark.y * height)
-                        if (
-                            landmark.x < 0
-                            or landmark.x > 1
-                            or landmark.y < 0
-                            or landmark.y > 1
-                        ):
+                        if landmark.x < 0 or landmark.x > 1 or landmark.y < 0 or landmark.y > 1:
                             # ignore
                             pass
                         else:
@@ -232,16 +202,12 @@ def run_frame_processor(self, port: int, rotation_count: int):
 
                 point_ids = np.array(point_ids)
                 landmark_xy = np.array(landmark_xy)
-                landmark_xy = unrotate_points(
-                    landmark_xy, rotation_count, width, height
-                )
+                landmark_xy = unrotate_points(landmark_xy, rotation_count, width, height)
                 point_packet = PointPacket(point_ids, landmark_xy)
 
                 self.out_queues[port].put(point_packet)
 
-    def get_points(
-        self, frame: np.ndarray, port: int, rotation_count: int
-    ) -> PointPacket:
+    def get_points(self, frame: np.ndarray, port: int, rotation_count: int) -> PointPacket:
         if port not in self.in_queues.keys():
             self.in_queues[port] = Queue(1)
             self.out_queues[port] = Queue(1)
diff --git a/caliscope/trackers/holistic_opensim_tracker.py b/caliscope/trackers/holistic_opensim_tracker.py
index a7c9c69a..2283ab28 100644
--- a/caliscope/trackers/holistic_opensim_tracker.py
+++ b/caliscope/trackers/holistic_opensim_tracker.py
@@ -1,15 +1,15 @@
-from threading import Thread
 from queue import Queue
+from threading import Thread
 
+import cv2
 import mediapipe as mp
 import numpy as np
-import cv2
 
+import caliscope.logger
 from caliscope.packets import PointPacket
 from caliscope.tracker import Tracker
 from caliscope.trackers.helper import apply_rotation, unrotate_points
 
-import caliscope.logger
 logger = caliscope.logger.get(__name__)
 
 MIN_DETECTION_CONFIDENCE = 0.5
@@ -217,39 +217,26 @@ def run_frame_processor(self, port: int, rotation_count: int):
                 landmark_xy = []
 
                 if results.pose_landmarks:
-                    for landmark_id, landmark in enumerate(
-                        results.pose_landmarks.landmark
-                    ):
+                    for landmark_id, landmark in enumerate(results.pose_landmarks.landmark):
                         # mediapipe expresses in terms of percent of frame, so must map to pixel position
                         x, y = int(landmark.x * width), int(landmark.y * height)
-                        if (
-                            landmark.x < 0
-                            or landmark.x > 1
-                            or landmark.y < 0
-                            or landmark.y > 1
-                        ):
+                        if landmark.x < 0 or landmark.x > 1 or landmark.y < 0 or landmark.y > 1:
                             # ignore
                             pass
                         else:
                             mapped_point_id = landmark_id + POSE_OFFSET
-                            # some of the pose values are too noisy to bother with including considering that holistic face and hand tracking is so good
+                            # some of the pose values are too noisy to bother with including considering that
+                            # holistic face and hand tracking is so good
                             # ignore those points that aren't in the POINT_NAMES list
                             if mapped_point_id in POINT_NAMES:
                                 point_ids.append(landmark_id + POSE_OFFSET)
                                 landmark_xy.append((x, y))
 
                 if results.right_hand_landmarks:
-                    for landmark_id, landmark in enumerate(
-                        results.right_hand_landmarks.landmark
-                    ):
+                    for landmark_id, landmark in enumerate(results.right_hand_landmarks.landmark):
                         # mediapipe expresses in terms of percent of frame, so must map to pixel position
                         x, y = int(landmark.x * width), int(landmark.y * height)
-                        if (
-                            landmark.x < 0
-                            or landmark.x > 1
-                            or landmark.y < 0
-                            or landmark.y > 1
-                        ):
+                        if landmark.x < 0 or landmark.x > 1 or landmark.y < 0 or landmark.y > 1:
                             # ignore
                             pass
                         else:
@@ -257,17 +244,10 @@ def run_frame_processor(self, port: int, rotation_count: int):
                             landmark_xy.append((x, y))
 
                 if results.left_hand_landmarks:
-                    for landmark_id, landmark in enumerate(
-                        results.left_hand_landmarks.landmark
-                    ):
+                    for landmark_id, landmark in enumerate(results.left_hand_landmarks.landmark):
                         # mediapipe expresses in terms of percent of frame, so must map to pixel positionND_OFFSET
                         x, y = int(landmark.x * width), int(landmark.y * height)
-                        if (
-                            landmark.x < 0
-                            or landmark.x > 1
-                            or landmark.y < 0
-                            or landmark.y > 1
-                        ):
+                        if landmark.x < 0 or landmark.x > 1 or landmark.y < 0 or landmark.y > 1:
                             # ignore
                             pass
                         else:
@@ -275,17 +255,10 @@ def run_frame_processor(self, port: int, rotation_count: int):
                             landmark_xy.append((x, y))
 
                 if results.face_landmarks:
-                    for landmark_id, landmark in enumerate(
-                        results.face_landmarks.landmark
-                    ):
+                    for landmark_id, landmark in enumerate(results.face_landmarks.landmark):
                         # mediapipe expresses in terms of percent of frame, so must map to pixel positionFSET
                         x, y = int(landmark.x * width), int(landmark.y * height)
-                        if (
-                            landmark.x < 0
-                            or landmark.x > 1
-                            or landmark.y < 0
-                            or landmark.y > 1
-                        ):
+                        if landmark.x < 0 or landmark.x > 1 or landmark.y < 0 or landmark.y > 1:
                             # ignore
                             pass
                         else:
@@ -300,16 +273,12 @@ def run_frame_processor(self, port: int, rotation_count: int):
                 landmark_xy = np.array(landmark_xy)
 
                 # adjust for previous shift due to camera rotation count
-                landmark_xy = unrotate_points(
-                    landmark_xy, rotation_count, width, height
-                )
+                landmark_xy = unrotate_points(landmark_xy, rotation_count, width, height)
                 point_packet = PointPacket(point_ids, landmark_xy)
 
                 self.out_queues[port].put(point_packet)
 
-    def get_points(
-        self, frame: np.ndarray, port: int, rotation_count: int
-    ) -> PointPacket:
+    def get_points(self, frame: np.ndarray, port: int, rotation_count: int) -> PointPacket:
         """
         This is the primary method exposed to the rest of the code.
         The tracker receives frames and basic camera data from the Stream,
diff --git a/caliscope/trackers/pose_tracker.py b/caliscope/trackers/pose_tracker.py
index 5f4acc71..5eb2c5e3 100644
--- a/caliscope/trackers/pose_tracker.py
+++ b/caliscope/trackers/pose_tracker.py
@@ -1,16 +1,17 @@
-import caliscope.logger
-
-from threading import Thread
 from queue import Queue
+from threading import Thread
 
+import cv2
 import mediapipe as mp
 import numpy as np
-import cv2
+
+import caliscope.logger
 
 # cap = cv2.VideoCapture(0)
-from caliscope.packets import  PointPacket
+from caliscope.packets import PointPacket
 from caliscope.tracker import Tracker
 from caliscope.trackers.helper import apply_rotation, unrotate_points
+
 logger = caliscope.logger.get(__name__)
 
 POINT_NAMES = {
@@ -53,7 +54,7 @@
 class PoseTracker(Tracker):
     def __init__(self) -> None:
         # each port gets its own mediapipe context manager
-        # use a dictionary of queues for passing 
+        # use a dictionary of queues for passing
         self.in_queues = {}
         self.out_queues = {}
         self.threads = {}
@@ -85,7 +86,6 @@ def run_frame_processor(self, port: int, rotation_count: int):
                 landmark_xy = []
 
                 if results.pose_landmarks:
-
                     for landmark_id, landmark in enumerate(results.pose_landmarks.landmark):
                         point_ids.append(landmark_id)
 
@@ -93,18 +93,14 @@ def run_frame_processor(self, port: int, rotation_count: int):
                         x, y = int(landmark.x * width), int(landmark.y * height)
                         landmark_xy.append((x, y))
 
-
                 point_ids = np.array(point_ids)
                 landmark_xy = np.array(landmark_xy)
-                landmark_xy = unrotate_points(landmark_xy, rotation_count, width,height)
+                landmark_xy = unrotate_points(landmark_xy, rotation_count, width, height)
                 point_packet = PointPacket(point_ids, landmark_xy)
 
                 self.out_queues[port].put(point_packet)
 
-
-    def get_points(
-        self, frame: np.ndarray, port: int, rotation_count: int
-    ) -> PointPacket:
+    def get_points(self, frame: np.ndarray, port: int, rotation_count: int) -> PointPacket:
         if port not in self.in_queues.keys():
             self.in_queues[port] = Queue(1)
             self.out_queues[port] = Queue(1)
@@ -130,8 +126,7 @@ def scatter_draw_instructions(self, point_id: int) -> dict:
             rules = {"radius": 5, "color": (0, 0, 220), "thickness": 3}
         elif self.get_point_name(point_id).startswith("right"):
             rules = {"radius": 5, "color": (220, 0, 0), "thickness": 3}
-        else: 
+        else:
             rules = {"radius": 5, "color": (220, 0, 220), "thickness": 3}
 
         return rules
-
diff --git a/caliscope/trackers/tracker_enum.py b/caliscope/trackers/tracker_enum.py
index 465fa986..3056ecc7 100644
--- a/caliscope/trackers/tracker_enum.py
+++ b/caliscope/trackers/tracker_enum.py
@@ -1,12 +1,12 @@
 from enum import Enum
 
-
 from caliscope.trackers.charuco_tracker import CharucoTracker
-from caliscope.trackers.hand_tracker  import  HandTracker
-from caliscope.trackers.pose_tracker import  PoseTracker
+from caliscope.trackers.face_tracker import FaceTracker
+from caliscope.trackers.hand_tracker import HandTracker
 from caliscope.trackers.holistic.holistic_tracker import HolisticTracker
 from caliscope.trackers.holistic_opensim_tracker import HolisticOpenSimTracker
-from caliscope.trackers.face_tracker import FaceTracker
+from caliscope.trackers.pose_tracker import PoseTracker
+
 
 class TrackerEnum(Enum):
     HAND = HandTracker
@@ -16,8 +16,7 @@ class TrackerEnum(Enum):
     CHARUCO = CharucoTracker
     FACE = FaceTracker
 
-    
-    
+
 if __name__ == "__main__":
     tracker_factories = [enum_member.name for enum_member in TrackerEnum]
     print(tracker_factories)
diff --git a/caliscope/trackers/wireframe_builder.py b/caliscope/trackers/wireframe_builder.py
index 05e66716..7af53e89 100644
--- a/caliscope/trackers/wireframe_builder.py
+++ b/caliscope/trackers/wireframe_builder.py
@@ -1,27 +1,31 @@
-import rtoml
 from pathlib import Path
+
+import rtoml
+
 import caliscope.logger
-from caliscope.tracker import WireFrameView, Segment
+from caliscope.tracker import Segment, WireFrameView
+
 logger = caliscope.logger.get(__name__)
 
-def get_wireframe(toml_spec_path: Path, point_names: dict)-> WireFrameView:
-    
-    # load in toml 
+
+def get_wireframe(toml_spec_path: Path, point_names: dict) -> WireFrameView:
+    # load in toml
     wireframe_specs = rtoml.load(toml_spec_path)
 
     logger.info(f"Building following wireframe: {wireframe_specs}")
 
     # build out a list of segments based on the dictionary
     segments = []
-    
+
     for segment_name, specs in wireframe_specs.items():
-        segment = Segment(name=segment_name,
-                          color=specs['color'],
-                          point_A=specs['points'][0],
-                          point_B=specs['points'][1],
-                          )
+        segment = Segment(
+            name=segment_name,
+            color=specs["color"],
+            point_A=specs["points"][0],
+            point_B=specs["points"][1],
+        )
         segments.append(segment)
 
-    wireframe = WireFrameView(segments=segments,point_names=point_names)        
+    wireframe = WireFrameView(segments=segments, point_names=point_names)
 
-    return wireframe
\ No newline at end of file
+    return wireframe
diff --git a/caliscope/triangulate/array_stereo_triangulator.py b/caliscope/triangulate/array_stereo_triangulator.py
index 9c78419e..2f0400ee 100644
--- a/caliscope/triangulate/array_stereo_triangulator.py
+++ b/caliscope/triangulate/array_stereo_triangulator.py
@@ -1,47 +1,44 @@
-import caliscope.logger
+from itertools import combinations
 
 import cv2
 import numpy as np
-from pathlib import Path
-from itertools import combinations
 
-from caliscope.triangulate.stereo_points_builder import StereoPointsBuilder, StereoPointsPacket, SynchedStereoPointsPacket
+import caliscope.logger
+from caliscope.cameras.camera_array import CameraArray, CameraData
+from caliscope.triangulate.stereo_points_builder import StereoPointsPacket, SynchedStereoPointsPacket
 from caliscope.triangulate.triangulation import undistort
-from caliscope.cameras.camera_array import CameraData, CameraArray
+
 logger = caliscope.logger.get(__name__)
 
+
 class ArrayStereoTriangulator:
-    
     def __init__(self, camera_array: CameraArray):
         self.camera_array = camera_array
-        
+
         # pull ports list from camera_array.port_index
         # to ensure only non-ignored cameras are processed
         self.ports = list(camera_array.port_index.keys())
-        self.pairs = [(i,j) for i,j in combinations(self.ports,2) if i<j]
-
+        self.pairs = [(i, j) for i, j in combinations(self.ports, 2) if i < j]
 
         # create the triangulators for each pair of cameras
         self.triangulators = {}
         for pair in self.pairs:
             port_A = pair[0]
             port_B = pair[1]
-            
-            camera_A:CameraData = self.camera_array.cameras[port_A]
-            camera_B:CameraData = self.camera_array.cameras[port_B]
+
+            camera_A: CameraData = self.camera_array.cameras[port_A]
+            camera_B: CameraData = self.camera_array.cameras[port_B]
 
             self.triangulators[pair] = StereoPairTriangulator(camera_A, camera_B)
-            
-    def triangulate_synched_points(self, synced_paired_points:SynchedStereoPointsPacket):
-        for pair,paired_point_packet  in synced_paired_points.stereo_points_packets.items():
+
+    def triangulate_synched_points(self, synced_paired_points: SynchedStereoPointsPacket):
+        for pair, paired_point_packet in synced_paired_points.stereo_points_packets.items():
             if paired_point_packet is not None:
                 self.triangulators[pair].add_3D_points(paired_point_packet)
 
 
-
 class StereoPairTriangulator:
     def __init__(self, camera_A: CameraData, camera_B: CameraData):
-
         self.camera_A = camera_A
         self.camera_B = camera_B
         self.portA = camera_A.port
@@ -51,7 +48,6 @@ def __init__(self, camera_A: CameraData, camera_B: CameraData):
         self.build_projection_matrices()
 
     def build_projection_matrices(self):
-
         # attempting to create something that integrates with the new set_cameras_refactor
         rot_trans_A = np.column_stack([self.camera_A.rotation, self.camera_A.translation])
         mtx_A = self.camera_A.matrix
@@ -61,22 +57,18 @@ def build_projection_matrices(self):
         mtx_B = self.camera_B.matrix
         self.proj_B = mtx_B @ rot_trans_B  # projection matrix for CamB
 
-    def add_3D_points(self, paired_points:StereoPointsPacket):
-            
+    def add_3D_points(self, paired_points: StereoPointsPacket):
         if len(paired_points.common_ids) > 0:
             xy_A = paired_points.img_loc_A
             xy_B = paired_points.img_loc_B
-         
-        if xy_A.shape[0] > 0:
 
-            points_A_undistorted = undistort(xy_A,self.camera_A)
-            points_B_undistorted = undistort(xy_B,self.camera_B)
+        if xy_A.shape[0] > 0:
+            points_A_undistorted = undistort(xy_A, self.camera_A)
+            points_B_undistorted = undistort(xy_B, self.camera_B)
 
             # triangulate points outputs data in 4D homogenous coordinate system
             # note that these are in a world frame of reference
-            xyzw_h = cv2.triangulatePoints(
-                self.proj_A, self.proj_B, points_A_undistorted, points_B_undistorted
-            )
+            xyzw_h = cv2.triangulatePoints(self.proj_A, self.proj_B, points_A_undistorted, points_B_undistorted)
 
             xyz_h = xyzw_h.T[:, :3]
             w = xyzw_h[3, :]
@@ -86,5 +78,3 @@ def add_3D_points(self, paired_points:StereoPointsPacket):
 
         # update the paired point packet with the 3d positions
         paired_points.xyz = xyz
-        
-        
\ No newline at end of file
diff --git a/caliscope/triangulate/stereo_points_builder.py b/caliscope/triangulate/stereo_points_builder.py
index 448a005f..9c3792d8 100644
--- a/caliscope/triangulate/stereo_points_builder.py
+++ b/caliscope/triangulate/stereo_points_builder.py
@@ -1,31 +1,23 @@
-
-from queue import Queue
-from threading import Thread, Event
-import cv2
-import sys
-from pathlib import Path
-import pandas as pd
-import numpy as np
+import logging
 from dataclasses import dataclass
 from itertools import combinations
-from caliscope.cameras.synchronizer import Synchronizer
-from caliscope.trackers.charuco_tracker import CharucoTracker
-from caliscope.packets import SyncPacket
+from pathlib import Path
+
+import numpy as np
 
-import logging
 import caliscope.logger
+from caliscope.cameras.synchronizer import Synchronizer
+from caliscope.packets import SyncPacket
 
 logger = caliscope.logger.get(__name__)
 
 
 class StereoPointsBuilder:
     def __init__(self, ports: list):
-
         self.ports = ports
         self.pairs = [(i, j) for i, j in combinations(self.ports, 2) if i < j]
 
     def get_stereo_points_packet(self, sync_index, port_A, points_A, port_B, points_B):
-
         # get ids in common
         if len(points_A.point_id) > 0 and len(points_B.point_id) > 0:
             common_ids = np.intersect1d(points_A.point_id, points_B.point_id)
@@ -38,15 +30,11 @@ def get_stereo_points_packet(self, sync_index, port_A, points_A, port_B, points_
             # common_ids = common_ids[:,0]
             # for both ports, get the indices of the common ids
             sorter_A = np.argsort(points_A.point_id)
-            shared_indices_A = sorter_A[
-                np.searchsorted(points_A.point_id, common_ids, sorter=sorter_A)
-            ]
+            shared_indices_A = sorter_A[np.searchsorted(points_A.point_id, common_ids, sorter=sorter_A)]
             shared_indices_A
 
             sorter_B = np.argsort(points_B.point_id)
-            shared_indices_B = sorter_B[
-                np.searchsorted(points_B.point_id, common_ids, sorter=sorter_B)
-            ]
+            shared_indices_B = sorter_B[np.searchsorted(points_B.point_id, common_ids, sorter=sorter_B)]
             shared_indices_B
 
             packet = StereoPointsPacket(
@@ -58,14 +46,11 @@ def get_stereo_points_packet(self, sync_index, port_A, points_A, port_B, points_
                 img_loc_B=points_B.img_loc[shared_indices_B],
             )
 
-            logger.debug(
-                f"Points in common for ports ({port_A}, {port_B}): {common_ids}"
-            )
+            logger.debug(f"Points in common for ports ({port_A}, {port_B}): {common_ids}")
 
         return packet
 
     def get_synched_paired_points(self, sync_packet: SyncPacket):
-
         # will be populated with dataframes of:
         # id | img_x | img_y | board_x | board_y
         sync_index = sync_packet.sync_index
@@ -75,11 +60,7 @@ def get_synched_paired_points(self, sync_packet: SyncPacket):
             port_A = pair[0]
             port_B = pair[1]
 
-            if (
-                sync_packet.frame_packets[port_A] is not None
-                and sync_packet.frame_packets[port_B] is not None
-            ):
-
+            if sync_packet.frame_packets[port_A] is not None and sync_packet.frame_packets[port_B] is not None:
                 points_A = sync_packet.frame_packets[port_A].points
                 points_B = sync_packet.frame_packets[port_B].points
 
@@ -139,7 +120,6 @@ class SynchedStereoPointsPacket:
     sync_index: int
     stereo_points_packets: dict
 
-
     @property
     def pairs(self):
         return list(self.stereo_points_packets.keys())
@@ -149,8 +129,8 @@ def to_table(self):
 
 
 if __name__ == "__main__":
-    from caliscope.recording.recorded_stream import RecordedStreamPool
     from caliscope.calibration.charuco import Charuco
+    from caliscope.recording.recorded_stream import RecordedStreamPool
 
     logger.setLevel(logging.DEBUG)
     from caliscope import __root__
@@ -160,9 +140,7 @@ def to_table(self):
 
     ports = [0, 1, 2, 3, 4]
 
-    tracker = Charuco(
-        4, 5, 11, 8.5, aruco_scale=0.75, square_size_overide_cm=5.25, inverted=True
-    )
+    tracker = Charuco(4, 5, 11, 8.5, aruco_scale=0.75, square_size_overide_cm=5.25, inverted=True)
 
     recorded_stream_pool = RecordedStreamPool(ports, session_directory, charuco=tracker)
     syncr = Synchronizer(recorded_stream_pool.streams, fps_target=200)
diff --git a/caliscope/triangulate/sync_packet_triangulator.py b/caliscope/triangulate/sync_packet_triangulator.py
index 950c5166..19b0e6fa 100644
--- a/caliscope/triangulate/sync_packet_triangulator.py
+++ b/caliscope/triangulate/sync_packet_triangulator.py
@@ -1,17 +1,19 @@
+from pathlib import Path
+from queue import Queue
+from threading import Event, Thread
+
 import numpy as np
 import pandas as pd
+
+import caliscope.logger
 from caliscope.cameras.camera_array import CameraArray
 from caliscope.cameras.synchronizer import Synchronizer, SyncPacket
-from queue import Queue
-from threading import Thread, Event
-from pathlib import Path
 from caliscope.packets import XYZPacket
-
 from caliscope.triangulate.triangulation import triangulate_sync_index
-import caliscope.logger
 
 logger = caliscope.logger.get(__name__)
 
+
 class SyncPacketTriangulator:
     """
     Will place 3d packets on subscribed queues and save consolidated data in csv
@@ -23,7 +25,7 @@ def __init__(
         camera_array: CameraArray,
         synchronizer: Synchronizer,
         recording_directory: Path = None,
-        tracker_name:str = None,  # used only for getting the point names and tracker name
+        tracker_name: str = None,  # used only for getting the point names and tracker name
     ):
         self.camera_array = camera_array
         self.synchronizer = synchronizer
@@ -46,7 +48,7 @@ def __init__(
         self.synchronizer.subscribe_to_sync_packets(self.sync_packet_in_q)
 
         self.projection_matrices = self.camera_array.projection_matrices
-        
+
         self.subscribers = []
         self.running = True
         self.thread = Thread(target=self.process_incoming, args=(), daemon=True)
@@ -69,9 +71,7 @@ def process_incoming(self):
             if sync_packet is None:
                 # No more sync packets after this... wind down
                 self.stop_thread.set()
-                logger.info(
-                    "End processing of incoming sync packets...end signaled with `None` packet"
-                )
+                logger.info("End processing of incoming sync packets...end signaled with `None` packet")
             else:
                 logger.debug(
                     f"Sync Packet {sync_packet.sync_index} acquired with {sync_packet.frame_packet_count} frames"
@@ -96,11 +96,9 @@ def process_incoming(self):
                             f"Synch Packet {sync_packet.sync_index} | Point ID: {point_id_xyz} | xyz: {points_xyz}"
                         )
 
-                        xyz_packet = XYZPacket(
-                            sync_packet.sync_index, point_id_xyz, points_xyz
-                        )
+                        xyz_packet = XYZPacket(sync_packet.sync_index, point_id_xyz, points_xyz)
                         logger.info(
-                            f"Placing xyz pacKet for index {sync_packet.sync_index} with {len(xyz_packet.point_ids)} points"
+                            f"Placing xyz pacKet for index {sync_packet.sync_index} with {len(xyz_packet.point_ids)} points"  # noqa E501
                         )
                         for q in self.subscribers:
                             q.put(xyz_packet)
@@ -125,20 +123,17 @@ def add_packet_to_history(self, xyz_packet: XYZPacket):
             self.xyz_history["x_coord"].extend(xyz_array[:, 0].tolist())
             self.xyz_history["y_coord"].extend(xyz_array[:, 1].tolist())
             self.xyz_history["z_coord"].extend(xyz_array[:, 2].tolist())
-            
-    
 
-    def save_history(self)->None:
+    def save_history(self) -> None:
         """
         If a recording directory is provided, then save the xyz directory into it
         If a tracker name is provided, then base name on the tracker name
         """
         df_xyz: pd.DataFrame = pd.DataFrame(self.xyz_history)
-       
-        if self.recording_directory is not None: 
+
+        if self.recording_directory is not None:
             if self.tracker_name is None:
                 filename = "xyz.csv"
             else:
                 filename = f"xyz_{self.tracker_name}.csv"
-                df_xyz.to_csv(Path(self.recording_directory,filename))
-
+                df_xyz.to_csv(Path(self.recording_directory, filename))
diff --git a/caliscope/triangulate/triangulation.py b/caliscope/triangulate/triangulation.py
index 5db693e4..2eb43ce4 100644
--- a/caliscope/triangulate/triangulation.py
+++ b/caliscope/triangulate/triangulation.py
@@ -1,14 +1,16 @@
+from time import time
 
-
-import caliscope.logger
+import numpy as np
 import pandas as pd
-from time import time
 from numba import jit
 from numba.typed import Dict, List
+
+import caliscope.logger
 from caliscope.cameras.camera_array import CameraArray, CameraData
-import numpy as np
+
 logger = caliscope.logger.get(__name__)
 
+
 # helper function to avoid use of np.unique(return_counts=True) which doesn't work with jit
 @jit(nopython=True, cache=True)
 def unique_with_counts(arr):
@@ -25,8 +27,9 @@ def unique_with_counts(arr):
 
     return np.array(unique_values), np.array(counts)
 
+
 #####################################################################################
-# The following code is adapted from the `Anipose` project, 
+# The following code is adapted from the `Anipose` project,
 # in particular the `triangulate_simple` function of `aniposelib`
 # Original author:  Lili Karashchuk
 # Project: https://github.com/lambdaloop/aniposelib/
@@ -41,11 +44,11 @@ def unique_with_counts(arr):
 # modification, are permitted provided that the following conditions are met:
 
 # 1. Redistributions of source code must retain the above copyright notice, this
-   # list of conditions and the following disclaimer.
+# list of conditions and the following disclaimer.
 
 # 2. Redistributions in binary form must reproduce the above copyright notice,
-   # this list of conditions and the following disclaimer in the documentation
-   # and/or other materials provided with the distribution.
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
 
 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -58,9 +61,10 @@ def unique_with_counts(arr):
 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+
 @jit(nopython=True, parallel=True, cache=True)
 def triangulate_sync_index(
-    projection_matrices:Dict, current_camera_indices:np.ndarray, current_point_id:np.ndarray, current_img:np.ndarray
+    projection_matrices: Dict, current_camera_indices: np.ndarray, current_point_id: np.ndarray, current_img: np.ndarray
 ):
     # sync_indices_xyz = List()
     point_indices_xyz = List()
@@ -89,21 +93,23 @@ def triangulate_sync_index(
             obj_xyz.append(point_xyz)
 
     return point_indices_xyz, obj_xyz
+
+
 # End of adapted code
 ##################################################################################
 
 
-def triangulate_xy(xy: pd.DataFrame, camera_array:CameraArray) -> pd.DataFrame:
+def triangulate_xy(xy: pd.DataFrame, camera_array: CameraArray) -> pd.DataFrame:
     """
     xy data comes in as viewed by the camera and it is undistorted as
     part of the triangulation process
-    """    
+    """
     # assemble numba compatible dictionary
     projection_matrices = camera_array.projection_matrices
 
-    # Code here to undistort all image points 
+    # Code here to undistort all image points
     undistorted_xy = undistort_batch(xy, camera_array)
-    
+
     xyz = {
         "sync_index": [],
         "point_id": [],
@@ -129,9 +135,7 @@ def triangulate_xy(xy: pd.DataFrame, camera_array:CameraArray) -> pd.DataFrame:
         raw_xy = np.vstack([img_loc_x, img_loc_y]).T
 
         # the fancy part
-        point_id_xyz, points_xyz = triangulate_sync_index(
-            projection_matrices, port, point_ids, raw_xy
-        )
+        point_id_xyz, points_xyz = triangulate_sync_index(projection_matrices, port, point_ids, raw_xy)
 
         if len(point_id_xyz) > 0:
             # there are points to store so store them...
@@ -145,10 +149,8 @@ def triangulate_xy(xy: pd.DataFrame, camera_array:CameraArray) -> pd.DataFrame:
 
         # only log percent complete each second
         if int(time()) - last_log_update >= 1:
-            percent_complete = int(100*(index/sync_index_max))
-            logger.info(
-                f"(Stage 2 of 2): Triangulation of (x,y) point estimates is {percent_complete}% complete"
-            )
+            percent_complete = int(100 * (index / sync_index_max))
+            logger.info(f"(Stage 2 of 2): Triangulation of (x,y) point estimates is {percent_complete}% complete")
             last_log_update = int(time())
 
     # convert to dataframe prior to returning
@@ -156,11 +158,10 @@ def triangulate_xy(xy: pd.DataFrame, camera_array:CameraArray) -> pd.DataFrame:
     return xyz
 
 
-
-def undistort(points, camera: CameraData, iter_num=3) -> np.ndarray: 
+def undistort(points, camera: CameraData, iter_num=3) -> np.ndarray:
     """
-    points: (n,2) dimensional np.ndarray 
-    returns: (2,n) dimensional np.ndarray... definitely not happy with this but not going to start refactoring this at this moment
+    points: (n,2) dimensional np.ndarray
+    returns: (2,n) dimensional np.ndarray
     """
 
     # implementing a function described here: https://yangyushi.github.io/code/2020/03/04/opencv-undistort.html
@@ -168,7 +169,7 @@ def undistort(points, camera: CameraData, iter_num=3) -> np.ndarray:
     k1, k2, p1, p2, k3 = camera.distortions
     fx, fy = camera.matrix[0, 0], camera.matrix[1, 1]
     cx, cy = camera.matrix[:2, 2]
-        
+
     x, y = points.T[0], points.T[1]
 
     x = (x - cx) / fx
@@ -186,20 +187,18 @@ def undistort(points, camera: CameraData, iter_num=3) -> np.ndarray:
     return np.array((x * fx + cx, y * fy + cy))
 
 
-def undistort_batch(xy_df:pd.DataFrame, camera_array:CameraArray)->pd.DataFrame:
-    
+def undistort_batch(xy_df: pd.DataFrame, camera_array: CameraArray) -> pd.DataFrame:
     undistorted_points = []
     for port, camera in camera_array.cameras.items():
         logger.info(f"Processing points from camera {port}")
         subset_xy = xy_df.query(f"port == {port}").copy()
-        points = np.vstack([subset_xy["img_loc_x"],subset_xy["img_loc_y"]]).T
-        x,y = undistort(points, camera)
+        points = np.vstack([subset_xy["img_loc_x"], subset_xy["img_loc_y"]]).T
+        x, y = undistort(points, camera)
         subset_xy["img_loc_undistort_x"] = x
         subset_xy["img_loc_undistort_y"] = y
         undistorted_points.append(subset_xy)
-        
+
     logger.info("Assembling undistorted dataframe")
 
     xy_undistorted_df = pd.concat(undistorted_points)
     return xy_undistorted_df
-    
\ No newline at end of file
diff --git a/caliscope/workspace_guide.py b/caliscope/workspace_guide.py
index 924f6ace..d3cc7f66 100644
--- a/caliscope/workspace_guide.py
+++ b/caliscope/workspace_guide.py
@@ -1,25 +1,24 @@
 from pathlib import Path
+
 import caliscope.logger
-from caliscope.cameras.camera_array import CameraArray
 from caliscope.configurator import Configurator
 
 logger = caliscope.logger.get(__name__)
 
+
 class WorkspaceGuide:
-    
     def __init__(self, workspace_dir, camera_count) -> None:
         self.workspace_dir = workspace_dir
         self.camera_count = camera_count
-        self.intrinsic_dir = Path(workspace_dir,"calibration","intrinsic")
-        self.extrinsic_dir = Path(workspace_dir,"calibration","extrinsic")
+        self.intrinsic_dir = Path(workspace_dir, "calibration", "intrinsic")
+        self.extrinsic_dir = Path(workspace_dir, "calibration", "extrinsic")
         self.recording_dir = Path(workspace_dir, "recordings")
 
-    
-    def get_ports_in_dir(self, directory:Path)->list:
+    def get_ports_in_dir(self, directory: Path) -> list:
         """
-        Returns a list of port indices that are currently exist in calibration/intrinsic 
+        Returns a list of port indices that are currently exist in calibration/intrinsic
         in the correct file format (i.e. 'port_#.mp4')
-        
+
         """
         all_ports = []
         for file in directory.iterdir():
@@ -27,33 +26,31 @@ def get_ports_in_dir(self, directory:Path)->list:
                 port = file.stem.split("_")[1]
                 all_ports.append(int(port))
         return all_ports
-        
 
     def all_instrinsic_mp4s_available(self):
         return self.missing_files_in_dir(self.intrinsic_dir) == "NONE"
-        
+
     def all_extrinsic_mp4s_available(self):
         return self.missing_files_in_dir(self.extrinsic_dir) == "NONE"
-        
-  
-    def missing_files_in_dir(self, directory:Path):
+
+    def missing_files_in_dir(self, directory: Path):
         files = []
-        target_ports = [i for i in range(1,self.camera_count+1)]
+        target_ports = [i for i in range(1, self.camera_count + 1)]
         current_ports = self.get_ports_in_dir(directory)
 
         missing_ports = [port for port in target_ports if port not in current_ports]
         for port in missing_ports:
             files.append(f"port_{port}.mp4")
-        
+
         missing_files = ",".join(files)
         if len(missing_files) == 0:
             missing_files = "NONE"
         return missing_files
-     
+
     def uncalibrated_cameras(self):
         uncalibrated = []
         for cam in self.camera_array.cameras.values():
-            if cam.distortions is None and cam.matrix is  None and cam.error is None:
+            if cam.distortions is None and cam.matrix is None and cam.error is None:
                 uncalibrated.append(str(cam.port))
 
         uncalibrated = ",".join(uncalibrated)
@@ -66,7 +63,7 @@ def intrinsic_calibration_status(self):
             return "COMPLETE"
         else:
             return "INCOMPLETE"
-         
+
     def extrinsic_calibration_status(self):
         if self.camera_array.all_extrinsics_calibrated() and self.all_extrinsic_mp4s_available():
             return "COMPLETE"
@@ -79,17 +76,17 @@ def valid_recording_dirs(self):
             if p.is_dir():
                 if self.missing_files_in_dir(p) == "NONE":
                     dir_list.append(p.stem)
-        
+
         return dir_list
-    
-    def valid_recording_dir_text(self)->str:
+
+    def valid_recording_dir_text(self) -> str:
         recording_dir_text = ",".join(self.valid_recording_dirs())
-    
-        if len(recording_dir_text)==0:
+
+        if len(recording_dir_text) == 0:
             recording_dir_text = "NONE"
         return recording_dir_text
-        
-    def get_html_summary(self)->str:
+
+    def get_html_summary(self) -> str:
         """
         Provide granular summary of where the workspace is in the calibration process
         Note that the currently configured camera array is reloaded each time this
@@ -104,7 +101,7 @@ def get_html_summary(self)->str:
                 <head>
                     <style>
                         p {{
-                            text-indent: 30px; 
+                            text-indent: 30px;
                         }}
                     </style>
                 </head>
@@ -123,15 +120,15 @@ def get_html_summary(self)->str:
                     <p>    valid directories: {self.valid_recording_dir_text()}</p>
                     <p>
                 </body>
-            </html> 
+            </html>
             """
-        
-        return html 
 
-        
-if __name__=="__main__":
+        return html
+
+
+if __name__ == "__main__":
     workspace_dir = Path(r"C:\Users\Mac Prible\OneDrive\caliscope\4_cam_prerecorded_practice_working")
     camera_count = 4
     workflow_guide = WorkspaceGuide(workspace_dir, camera_count)
 
-    logger.info(workflow_guide.get_html_summary())
\ No newline at end of file
+    logger.info(workflow_guide.get_html_summary())
diff --git a/dev/demo/demo_gui_capture_volume.py b/dev/demo/demo_gui_capture_volume.py
index ed00bdfc..a522c034 100644
--- a/dev/demo/demo_gui_capture_volume.py
+++ b/dev/demo/demo_gui_capture_volume.py
@@ -2,7 +2,6 @@
 import sys
 from pathlib import Path
 from caliscope.controller import Controller
-from caliscope.gui.post_processing_widget import PostProcessingWidget
 from caliscope.gui.vizualize.calibration.capture_volume_widget import CaptureVolumeWidget
 
 app = QApplication(sys.argv)
@@ -16,4 +15,3 @@
 window.show()
 
 app.exec()
-
diff --git a/dev/demo/demo_gui_main.py b/dev/demo/demo_gui_main.py
index 296de3cc..3e357970 100644
--- a/dev/demo/demo_gui_main.py
+++ b/dev/demo/demo_gui_main.py
@@ -12,4 +12,4 @@
 
 window.launch_workspace(str(workspace_dir))
 window.show()
-app.exec()
\ No newline at end of file
+app.exec()
diff --git a/dev/demo/demo_gui_post_processing.py b/dev/demo/demo_gui_post_processing.py
index bc6cc081..490406b3 100644
--- a/dev/demo/demo_gui_post_processing.py
+++ b/dev/demo/demo_gui_post_processing.py
@@ -5,7 +5,9 @@
 from caliscope.gui.post_processing_widget import PostProcessingWidget
 
 app = QApplication(sys.argv)
-workspace_dir = Path(r"C:\Users\Mac Prible\OneDrive - The University of Texas at Austin\research\caliscope\example_project")
+workspace_dir = Path(
+    r"C:\Users\Mac Prible\OneDrive - The University of Texas at Austin\research\caliscope\example_project"
+)
 
 controller = Controller(workspace_dir)
 controller.load_camera_array()
@@ -15,4 +17,3 @@
 window.show()
 
 app.exec()
-
diff --git a/dev/demo/demo_gui_triangulation_visualizer.py b/dev/demo/demo_gui_triangulation_visualizer.py
index e8a0c3e4..cb40095b 100644
--- a/dev/demo/demo_gui_triangulation_visualizer.py
+++ b/dev/demo/demo_gui_triangulation_visualizer.py
@@ -6,17 +6,21 @@
 from caliscope.trackers.holistic.holistic_tracker import HolisticTracker
 
 app = QApplication(sys.argv)
-workspace_dir = Path(r"C:\Users\Mac Prible\OneDrive - The University of Texas at Austin\research\caliscope\example_project")
+workspace_dir = Path(
+    r"C:\Users\Mac Prible\OneDrive - The University of Texas at Austin\research\caliscope\example_project"
+)
 
 controller = Controller(workspace_dir)
 controller.load_camera_array()
 camera_array = controller.camera_array
 tracker = HolisticTracker()
 
-xyz_history = Path(workspace_dir, "recordings","test_recording", "HOLISTIC", "xyz_HOLISTIC.csv")
-window = PlaybackTriangulationWidget(camera_array=camera_array,xyz_history_path=xyz_history, )
+xyz_history = Path(workspace_dir, "recordings", "test_recording", "HOLISTIC", "xyz_HOLISTIC.csv")
+window = PlaybackTriangulationWidget(
+    camera_array=camera_array,
+    xyz_history_path=xyz_history,
+)
 
 window.show()
 
 app.exec()
-
diff --git a/dev/demo/demo_synched_frames_widget.py b/dev/demo/demo_synched_frames_widget.py
index e5549ee2..c81a3fa8 100644
--- a/dev/demo/demo_synched_frames_widget.py
+++ b/dev/demo/demo_synched_frames_widget.py
@@ -35,5 +35,3 @@
 window.resize(800, 600)
 logger.info("About to show window")
 sys.exit(app.exec())
-
-
diff --git a/dev/dev_cross_corr_sync.py b/dev/dev_cross_corr_sync.py
index 97274ce5..f7cd41a4 100644
--- a/dev/dev_cross_corr_sync.py
+++ b/dev/dev_cross_corr_sync.py
@@ -1,72 +1,69 @@
-
-#%%
+# %%
 from plotnine import *
+
 # from caliscope.logger import get
 # logger = get(__name__)
-import cv2
-from threading import Thread
-import time
 import polars as pl
-import numpy as np
 from pathlib import Path
 
 
-recording_directory = Path(
-    r"C:\Users\Mac Prible\OneDrive\caliscope\test_record\recording_1"
-)
+recording_directory = Path(r"C:\Users\Mac Prible\OneDrive\caliscope\test_record\recording_1")
 
-data = pl.read_csv(Path(recording_directory,"combined_gap_filled_alt.csv"))
+data = pl.read_csv(Path(recording_directory, "combined_gap_filled_alt.csv"))
 
-#%%
+# %%
 c = pl.col
 
-def assign_tracked_group(df:pl.DataFrame):
-    change_mask  = df.with_columns((c("frame_delta")!=c("frame_delta").shift()).alias("change_mask"))
+
+def assign_tracked_group(df: pl.DataFrame):
+    change_mask = df.with_columns((c("frame_delta") != c("frame_delta").shift()).alias("change_mask"))
     return change_mask.with_columns(c("change_mask").cumsum().alias("tracked_subgroup"))
 
+
 def normalize_y_displacement(df: pl.DataFrame) -> pl.DataFrame:
-    mean_y = df['img_loc_y'].mean()
-    std_y = df['img_loc_y'].std()
-    
-    mean_x = df['img_loc_x'].mean()
-    std_x = df['img_loc_x'].std()
-
-    df = (df.with_columns(((c('img_loc_x') - mean_x) / std_x).alias("norm_x"))
-            .with_columns(((c('img_loc_y') - mean_y) / std_y).alias("norm_y"))
+    mean_y = df["img_loc_y"].mean()
+    std_y = df["img_loc_y"].std()
+
+    mean_x = df["img_loc_x"].mean()
+    std_x = df["img_loc_x"].std()
+
+    df = df.with_columns(((c("img_loc_x") - mean_x) / std_x).alias("norm_x")).with_columns(
+        ((c("img_loc_y") - mean_y) / std_y).alias("norm_y")
     )
     return df
 
-def assign_tracked_group_size(df:pl.DataFrame):
+
+def assign_tracked_group_size(df: pl.DataFrame):
     counts = df.groupby("track_id").agg(c("port").count().alias("track_group_size"))
-    return df.join(counts, on="track_id") 
+    return df.join(counts, on="track_id")
+
 
 # Applying the function in the pipeline
-df_sync = (data
-            .sort(["port", "point_id", "frame_index"])
-            .with_columns((c("frame_index") - c("frame_index").shift()).alias("frame_delta"))
-            .groupby(["port", "point_id"]).apply(assign_tracked_group)
-            .with_columns(pl.concat_str([c("port"), c("point_id"), c("tracked_subgroup")], separator="_").alias("track_id"))
-            .groupby("track_id").apply(normalize_y_displacement)
-            .pipe(assign_tracked_group_size)
-           )
+df_sync = (
+    data.sort(["port", "point_id", "frame_index"])
+    .with_columns((c("frame_index") - c("frame_index").shift()).alias("frame_delta"))
+    .groupby(["port", "point_id"])
+    .apply(assign_tracked_group)
+    .with_columns(pl.concat_str([c("port"), c("point_id"), c("tracked_subgroup")], separator="_").alias("track_id"))
+    .groupby("track_id")
+    .apply(normalize_y_displacement)
+    .pipe(assign_tracked_group_size)
+)
 
 df_sync
 
-#%%
-
-df_plt =(df_sync
-        #  .filter(c("port").is_in([0]))
-         .filter(c("point_id")==4)
-         .filter(c("track_group_size")>40)
-        #  .to_pandas()
-
-        )
-df_plt.write_csv(Path(recording_directory,"inspect.csv" ))
-plot = (ggplot(df_plt)+
-        aes(x="frame_time", y = "norm_y", color = "track_id")+
-        facet_grid("port ~ point_id")+
-        geom_point()
-        # theme(legend_position='none')
+# %%
+
+df_plt = (
+    df_sync
+    #  .filter(c("port").is_in([0]))
+    .filter(c("point_id") == 4).filter(c("track_group_size") > 40)
+    #  .to_pandas()
+)
+df_plt.write_csv(Path(recording_directory, "inspect.csv"))
+plot = (
+    ggplot(df_plt) + aes(x="frame_time", y="norm_y", color="track_id") + facet_grid("port ~ point_id") + geom_point()
+    # theme(legend_position='none')
 )
 plot
 # %%
diff --git a/poetry.lock b/poetry.lock
index 84fd1789..a3324f2a 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
 
 [[package]]
 name = "absl-py"
@@ -73,52 +73,6 @@ files = [
 [package.extras]
 dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"]
 
-[[package]]
-name = "black"
-version = "23.12.1"
-description = "The uncompromising code formatter."
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "black-23.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2"},
-    {file = "black-23.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba"},
-    {file = "black-23.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0"},
-    {file = "black-23.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3"},
-    {file = "black-23.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba"},
-    {file = "black-23.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b"},
-    {file = "black-23.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59"},
-    {file = "black-23.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50"},
-    {file = "black-23.12.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e"},
-    {file = "black-23.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec"},
-    {file = "black-23.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e"},
-    {file = "black-23.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9"},
-    {file = "black-23.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f"},
-    {file = "black-23.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d"},
-    {file = "black-23.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a"},
-    {file = "black-23.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e"},
-    {file = "black-23.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055"},
-    {file = "black-23.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54"},
-    {file = "black-23.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea"},
-    {file = "black-23.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2"},
-    {file = "black-23.12.1-py3-none-any.whl", hash = "sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e"},
-    {file = "black-23.12.1.tar.gz", hash = "sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5"},
-]
-
-[package.dependencies]
-click = ">=8.0.0"
-mypy-extensions = ">=0.4.3"
-packaging = ">=22.0"
-pathspec = ">=0.9.0"
-platformdirs = ">=2"
-tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
-typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
-
-[package.extras]
-colorama = ["colorama (>=0.4.3)"]
-d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
-jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
-uvloop = ["uvloop (>=0.15.2)"]
-
 [[package]]
 name = "certifi"
 version = "2023.11.17"
@@ -1204,17 +1158,6 @@ files = [
     {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"},
 ]
 
-[[package]]
-name = "mypy-extensions"
-version = "1.0.0"
-description = "Type system extensions for programs checked with the mypy type checker."
-optional = false
-python-versions = ">=3.5"
-files = [
-    {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
-    {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
-]
-
 [[package]]
 name = "nest-asyncio"
 version = "1.6.0"
@@ -2271,6 +2214,33 @@ files = [
     {file = "rtoml-0.9.0.tar.gz", hash = "sha256:113f2e133d152d9424269c475b4a7d0679987078b543e88fcb16c870dc2c460d"},
 ]
 
+[[package]]
+name = "ruff"
+version = "0.6.5"
+description = "An extremely fast Python linter and code formatter, written in Rust."
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "ruff-0.6.5-py3-none-linux_armv6l.whl", hash = "sha256:7e4e308f16e07c95fc7753fc1aaac690a323b2bb9f4ec5e844a97bb7fbebd748"},
+    {file = "ruff-0.6.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:932cd69eefe4daf8c7d92bd6689f7e8182571cb934ea720af218929da7bd7d69"},
+    {file = "ruff-0.6.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3a8d42d11fff8d3143ff4da41742a98f8f233bf8890e9fe23077826818f8d680"},
+    {file = "ruff-0.6.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a50af6e828ee692fb10ff2dfe53f05caecf077f4210fae9677e06a808275754f"},
+    {file = "ruff-0.6.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:794ada3400a0d0b89e3015f1a7e01f4c97320ac665b7bc3ade24b50b54cb2972"},
+    {file = "ruff-0.6.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:381413ec47f71ce1d1c614f7779d88886f406f1fd53d289c77e4e533dc6ea200"},
+    {file = "ruff-0.6.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:52e75a82bbc9b42e63c08d22ad0ac525117e72aee9729a069d7c4f235fc4d276"},
+    {file = "ruff-0.6.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09c72a833fd3551135ceddcba5ebdb68ff89225d30758027280968c9acdc7810"},
+    {file = "ruff-0.6.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:800c50371bdcb99b3c1551d5691e14d16d6f07063a518770254227f7f6e8c178"},
+    {file = "ruff-0.6.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e25ddd9cd63ba1f3bd51c1f09903904a6adf8429df34f17d728a8fa11174253"},
+    {file = "ruff-0.6.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7291e64d7129f24d1b0c947ec3ec4c0076e958d1475c61202497c6aced35dd19"},
+    {file = "ruff-0.6.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9ad7dfbd138d09d9a7e6931e6a7e797651ce29becd688be8a0d4d5f8177b4b0c"},
+    {file = "ruff-0.6.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:005256d977021790cc52aa23d78f06bb5090dc0bfbd42de46d49c201533982ae"},
+    {file = "ruff-0.6.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:482c1e6bfeb615eafc5899127b805d28e387bd87db38b2c0c41d271f5e58d8cc"},
+    {file = "ruff-0.6.5-py3-none-win32.whl", hash = "sha256:cf4d3fa53644137f6a4a27a2b397381d16454a1566ae5335855c187fbf67e4f5"},
+    {file = "ruff-0.6.5-py3-none-win_amd64.whl", hash = "sha256:3e42a57b58e3612051a636bc1ac4e6b838679530235520e8f095f7c44f706ff9"},
+    {file = "ruff-0.6.5-py3-none-win_arm64.whl", hash = "sha256:51935067740773afdf97493ba9b8231279e9beef0f2a8079188c4776c25688e0"},
+    {file = "ruff-0.6.5.tar.gz", hash = "sha256:4d32d87fab433c0cf285c3683dd4dae63be05fd7a1d65b3f5bf7cdd05a6b96fb"},
+]
+
 [[package]]
 name = "scipy"
 version = "1.12.0"
@@ -2433,17 +2403,6 @@ files = [
 docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"]
 test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"]
 
-[[package]]
-name = "typing-extensions"
-version = "4.9.0"
-description = "Backported and Experimental Type Hints for Python 3.8+"
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"},
-    {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"},
-]
-
 [[package]]
 name = "urllib3"
 version = "2.1.0"
@@ -2513,4 +2472,4 @@ files = [
 [metadata]
 lock-version = "2.0"
 python-versions = ">=3.10, <3.12"
-content-hash = "2174076cbdedc4452f17e9f8f0097b8056a2ca332a5a41307040605b50ce34ca"
+content-hash = "4cb2457422c48f5f863659979099b5195d0b9a10cf050fe51b9d4f9432350940"
diff --git a/pyproject.toml b/pyproject.toml
index a2055ecd..a4c4ec41 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -21,12 +21,12 @@ rtoml = "^0.9.0"
 pyarrow = "^15.0.0"
 
 [tool.poetry.group.dev.dependencies]
-black = "^23.3.0"
 pytest = "^7.3.0"
 ipykernel = "^6.22.0"
 pymdown-extensions = ">=9.11,<11.0"
 mkdocs-material = "^9.1.6"
 mkdocs-git-revision-date-localized-plugin = "^1.2.0"
+ruff = "^0.6.5"
 
 [build-system]
 requires = ["poetry-core"]
@@ -39,4 +39,56 @@ repository = "https://github.com/mprib/caliscope"
 caliscope = "caliscope.__main__:CLI_parser"
 
 [tool.setuptools_scm]
-write_to = "caliscope/_version.py"
\ No newline at end of file
+write_to = "caliscope/_version.py"
+
+
+[tool.ruff]
+lint.select = ["E", "F", "W","I"]
+lint.ignore = []
+unsafe-fixes = true
+
+# Allow autofix for all enabled rules (when `--fix`) is provided.
+lint.fixable = ["E", "F", "W","I"]
+# lint.fixable = ["A", "B", "C", "D", "E", "F", "G", "I", "N", "Q", "S", "T", "W", "ANN", "ARG", "BLE", "COM", "DJ", "DTZ", "EM", "ERA", "EXE", "FBT", "ICN", "INP", "ISC", "NPY", "PD", "PGH", "PIE", "PL", "PT", "PTH", "PYI", "RET", "RSE", "RUF", "SIM", "SLF", "TCH", "TID", "TRY", "UP", "YTT"]
+lint.unfixable = []
+
+# Exclude a variety of commonly ignored directories.
+exclude = [
+    ".bzr",
+    ".direnv",
+    ".eggs",
+    ".git",
+    ".hg",
+    ".mypy_cache",
+    ".nox",
+    ".pants.d",
+    ".pytype",
+    ".ruff_cache",
+    ".svn",
+    ".tox",
+    ".venv",
+    "__pypackages__",
+    "_build",
+    "buck-out",
+    "build",
+    "dist",
+    "node_modules",
+    "venv",
+    "dev",
+]
+
+line-length = 120
+
+# Allow unused variables when underscore-prefixed.
+lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
+
+# Assume Python 3.10.
+target-version = "py310"
+
+[tool.ruff.format]
+
+
+
+[tool.ruff.lint.mccabe]
+# Unlike Flake8, default to a complexity level of 10.
+max-complexity = 10
\ No newline at end of file


Test patch:
diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml
index bd47f546..2870c89d 100644
--- a/.github/workflows/pytest.yml
+++ b/.github/workflows/pytest.yml
@@ -11,12 +11,13 @@ on:
 
 jobs:
   test:
-    runs-on: ubuntu-latest
+    runs-on: ${{ matrix.os }} 
     if: >
       github.event.pull_request.merged == true ||
       github.event_name == 'workflow_dispatch'
 
     strategy:
+      fail-fast: true
       matrix:
         python-version: ['3.10','3.11']
         os: [ubuntu-latest, macos-latest, windows-latest]
@@ -29,40 +30,38 @@ jobs:
             path: ~\AppData\Local\pip\Cache
 
     steps:
-    - uses: actions/checkout@v2
+    - name: Checkout Code
+      uses: actions/checkout@v4
 
     - name: Set up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v5
       with:
         python-version: ${{ matrix.python-version }}
 
-    # note this install is likely relevant for all ubuntu users...
-    # taken from https://www.reddit.com/r/github/comments/10aenmk/help_linux_action_cant_find_opengl_all_of_a_sudden/
-    - name: Update packages
+      # Ubuntu-specific steps
+    - name: Update packages (Ubuntu)
+      if: runner.os == 'Linux'
       run: sudo apt-get update
-
-    - name: Install packages
+    - name: Install packages (Ubuntu)
+      if: runner.os == 'Linux'
       run: sudo apt-get install --fix-missing libgl1-mesa-dev
-
-    # - name: Install X11 and xcb dependencies
-    #   run: |
-    #     sudo apt-get update
-    #     sudo apt-get install -y xvfb libxcb1 x11-apps
-      
-    - name: Install Poetry
-      run: |
-        curl -sSL https://install.python-poetry.org | python3 -
-
-    - name: Configure Poetry
+    
+    # macOS-specific steps
+    - name: Set environment variables (macOS)
+      if: runner.os == 'macOS'
       run: |
-        echo "$HOME/.local/bin" >> $GITHUB_PATH
-        poetry config virtualenvs.create false
+        echo "MKL_NUM_THREADS=1" >> $GITHUB_ENV
+        echo "NUMEXPR_NUM_THREADS=1" >> $GITHUB_ENV
+        echo "OMP_NUM_THREADS=1" >> $GITHUB_ENV
 
     - name: Install dependencies
-      run: poetry install
-
-    # - name: Run tests with xvfb
-    #   run: xvfb-run --auto-servernum --server-args='-screen 0, 1024x768x24' poetry run pytest
+      run: |
+        python -m pip install --upgrade pip
+        python -m pip install ruff pytest
+        pip install -e .
 
-    - name: Run tests 
-      run: poetry run pytest
+    - name: Lint with Ruff
+      run: ruff check .
+    - name: Test with pytest
+      run: pytest
+        
\ No newline at end of file
diff --git a/tests/test_calibration.py b/tests/test_calibration.py
index a2325006..93ef82d6 100644
--- a/tests/test_calibration.py
+++ b/tests/test_calibration.py
@@ -1,27 +1,25 @@
-import caliscope.logger
-
-from time import sleep
 import shutil
 from pathlib import Path
-from caliscope.cameras.camera_array import CameraArray
+from time import sleep
+
+import pytest
+
+import caliscope.logger
 from caliscope import __root__
 from caliscope.calibration.capture_volume.capture_volume import CaptureVolume
-from caliscope.cameras.camera_array_initializer import CameraArrayInitializer
-from caliscope.calibration.capture_volume.point_estimates import PointEstimates
 from caliscope.calibration.capture_volume.helper_functions.get_point_estimates import (
     get_point_estimates,
 )
-import pytest
-from caliscope.trackers.charuco_tracker import CharucoTracker
-
-from caliscope.calibration.stereocalibrator import StereoCalibrator
+from caliscope.calibration.capture_volume.point_estimates import PointEstimates
 from caliscope.calibration.capture_volume.quality_controller import QualityController
-
-from caliscope.synchronized_stream_manager import SynchronizedStreamManager
-from caliscope.helper import copy_contents
-
-from caliscope.controller import FILTERED_FRACTION
+from caliscope.calibration.stereocalibrator import StereoCalibrator
+from caliscope.cameras.camera_array import CameraArray
+from caliscope.cameras.camera_array_initializer import CameraArrayInitializer
 from caliscope.configurator import Configurator
+from caliscope.controller import FILTERED_FRACTION
+from caliscope.helper import copy_contents
+from caliscope.synchronized_stream_manager import SynchronizedStreamManager
+from caliscope.trackers.charuco_tracker import CharucoTracker
 
 logger = caliscope.logger.get(__name__)
 
@@ -81,11 +79,11 @@ def test_post_monocalibration(session_path):
     logger.info("Creating RecordedStreamPool")
 
     recording_path = Path(session_path, "calibration", "extrinsic")
-    point_data_path = Path(recording_path,"CHARUCO", "xy_CHARUCO.csv")
+    point_data_path = Path(recording_path, "CHARUCO", "xy_CHARUCO.csv")
 
     camera_array = config.get_camera_array()
     sync_stream_manager = SynchronizedStreamManager(
-        recording_dir=recording_path, all_camera_data= camera_array.cameras, tracker=charuco_tracker
+        recording_dir=recording_path, all_camera_data=camera_array.cameras, tracker=charuco_tracker
     )
     sync_stream_manager.process_streams(fps_target=100)
 
@@ -98,9 +96,7 @@ def test_post_monocalibration(session_path):
     stereocalibrator = StereoCalibrator(config.config_toml_path, point_data_path)
     stereocalibrator.stereo_calibrate_all(boards_sampled=10)
 
-    camera_array: CameraArray = CameraArrayInitializer(
-        config.config_toml_path
-    ).get_best_camera_array()
+    camera_array: CameraArray = CameraArrayInitializer(config.config_toml_path).get_best_camera_array()
 
     point_estimates: PointEstimates = get_point_estimates(camera_array, point_data_path)
 
diff --git a/tests/test_configurator.py b/tests/test_configurator.py
index a98f431a..ad848744 100644
--- a/tests/test_configurator.py
+++ b/tests/test_configurator.py
@@ -1,57 +1,57 @@
 # more attributes could certainly be tested in here,but at least this gives some basic sense of if things
 # are working....
-import caliscope.logger
-
+import shutil
 from pathlib import Path
+
 import numpy as np
-import os
-import shutil
 
+import caliscope.logger
 from caliscope import __root__
+from caliscope.calibration.capture_volume.point_estimates import PointEstimates
+from caliscope.calibration.charuco import Charuco
+from caliscope.cameras.camera_array import CameraArray, CameraData
 from caliscope.configurator import Configurator
 from caliscope.helper import copy_contents
-from caliscope.cameras.camera_array import CameraArray, CameraData
-from caliscope.calibration.charuco import Charuco
-from caliscope.calibration.capture_volume.point_estimates import PointEstimates
 
 logger = caliscope.logger.get(__name__)
 
+
 def point_estimates_are_equal(pe1: PointEstimates, pe2: PointEstimates) -> bool:
     return (
-        np.array_equal(pe1.sync_indices, pe2.sync_indices) and
-        np.array_equal(pe1.camera_indices, pe2.camera_indices) and
-        np.array_equal(pe1.point_id, pe2.point_id) and
-        np.array_equal(pe1.img, pe2.img) and
-        np.array_equal(pe1.obj_indices, pe2.obj_indices) and
-        np.array_equal(pe1.obj, pe2.obj)
+        np.array_equal(pe1.sync_indices, pe2.sync_indices)
+        and np.array_equal(pe1.camera_indices, pe2.camera_indices)
+        and np.array_equal(pe1.point_id, pe2.point_id)
+        and np.array_equal(pe1.img, pe2.img)
+        and np.array_equal(pe1.obj_indices, pe2.obj_indices)
+        and np.array_equal(pe1.obj, pe2.obj)
     )
 
+
 def test_configurator():
     # provided with a path, load toml or create a default toml.
     dev_toml_path = Path(__root__, "tests", "sessions", "post_optimization")
     test_delete_path = Path(__root__, "tests", "sessions_copy_delete", "post_optimization")
 
-    copy_contents(dev_toml_path,test_delete_path)
+    copy_contents(dev_toml_path, test_delete_path)
 
     config = Configurator(test_delete_path)
 
     # load camera array
     camera_array = config.get_camera_array()
-    assert(isinstance(camera_array, CameraArray))
+    assert isinstance(camera_array, CameraArray)
 
     config.save_camera_array(camera_array)
 
     config2 = Configurator(test_delete_path)
     camera_array2 = config2.get_camera_array()
 
-
     # make sure that the rodrigues conversion isn't messing with anything...
-    np.testing.assert_array_almost_equal(camera_array.cameras[0].rotation,camera_array2.cameras[0].rotation, decimal=9)
+    np.testing.assert_array_almost_equal(camera_array.cameras[0].rotation, camera_array2.cameras[0].rotation, decimal=9)
 
     # load charuco
     charuco = config.get_charuco()
-    assert(isinstance(charuco, Charuco))
-    assert(charuco.columns==4)
+    assert isinstance(charuco, Charuco)
+    assert charuco.columns == 4
 
     # make a change to charuco and save it
     charuco.columns = 12
@@ -59,31 +59,31 @@ def test_configurator():
 
     # confirm change gets reflected when reloaded
     new_charuco = config.get_charuco()
-    assert(new_charuco.columns==12)
+    assert new_charuco.columns == 12
 
-    
     # load point estimates
     logger.info("Getting point estimates from config...")
     point_estimates = config.get_point_estimates()
-    assert(type(point_estimates)==PointEstimates)
+    assert isinstance(point_estimates, PointEstimates)
 
     # delete point estimates data
     config.point_estimates_toml_path.unlink()
     assert not config.point_estimates_toml_path.exists()
-     
-    # save point estimates stored in memory 
+
+    # save point estimates stored in memory
     config.save_point_estimates(point_estimates)
-    
-    # confirm it exists 
+
+    # confirm it exists
     assert config.point_estimates_toml_path.exists()
     config.refresh_point_estimates_from_toml()
-    
+
     # create new point estimates with newly saved data
     point_estimates_reloaded = config.get_point_estimates()
-    assert(type(point_estimates_reloaded)==PointEstimates)
+    assert isinstance(point_estimates_reloaded, PointEstimates)
 
     assert point_estimates_are_equal(point_estimates, point_estimates_reloaded)
 
+
 def remove_all_files_and_folders(directory_path):
     for item in directory_path.iterdir():
         if item.is_dir():
@@ -95,40 +95,40 @@ def remove_all_files_and_folders(directory_path):
 def test_new_cameras():
     """
     With the switch from toml to rtoml, differences in saving `None` values is resulting
-    in an inability to load new partially calibrated cameras. 
-    
+    in an inability to load new partially calibrated cameras.
+
     This test ensures that newly created cameras can be stored and reloaded via config
-    and will remain the same.   
+    and will remain the same.
     """
-    
+
     blank_workspace = Path(__root__, "tests", "sessions_copy_delete", "blank_workspace")
     if blank_workspace.exists():
         shutil.rmtree(blank_workspace)
     blank_workspace.mkdir(exist_ok=False)
-    
+
     config = Configurator(blank_workspace)
 
     # note that it appears rtoml will store tuples as lists,
     # so just keep everything a list for comparison purposes
-    cam_1 = CameraData(port=1, size=[1280,720])
-    cam_2 = CameraData(port=2, size=[1280,720])
-                                     
-    cameras = {1:cam_1, 2:cam_2}     
+    cam_1 = CameraData(port=1, size=[1280, 720])
+    cam_2 = CameraData(port=2, size=[1280, 720])
+
+    cameras = {1: cam_1, 2: cam_2}
     camera_array = CameraArray(cameras)
     config.save_camera_array(camera_array)
     print(camera_array.cameras)
-   
-    # with camera array saved by configurator, there are now many "null" values 
+
+    # with camera array saved by configurator, there are now many "null" values
     # populated in the toml file. Need to make sure that these are loaded correctly
-    
+
     config_copy = Configurator(blank_workspace)
     camera_array_copy = config_copy.get_camera_array()
     print(camera_array_copy.cameras)
-    
-    assert(camera_array.cameras[1] == camera_array_copy.cameras[1])    
-    assert(camera_array.cameras[2] == camera_array_copy.cameras[2])    
-    
+
+    assert camera_array.cameras[1] == camera_array_copy.cameras[1]
+    assert camera_array.cameras[2] == camera_array_copy.cameras[2]
+
+
 if __name__ == "__main__":
     # test_configurator()
     test_new_cameras()
-    
diff --git a/tests/test_controller.py b/tests/test_controller.py
index 9e6412a3..4a45fa15 100644
--- a/tests/test_controller.py
+++ b/tests/test_controller.py
@@ -1,27 +1,24 @@
-
-#%% 
+# %%
 from pathlib import Path
 from time import sleep
-from PySide6.QtWidgets import QApplication
 
+import caliscope.logger
 from caliscope import __root__
-from caliscope.cameras.camera_array import CameraArray
-from caliscope.helper import copy_contents
 from caliscope.controller import Controller, read_video_properties
-import caliscope.logger
-
+from caliscope.helper import copy_contents
 
 logger = caliscope.logger.get(__name__)
 
+
 def test_extrinsic_calibration():
     # app = QApplication()  # must exist prior to QPixels which are downstream when controller is created
     original_workspace = Path(__root__, "tests", "sessions", "post_monocal")
-    workspace = Path( __root__, "tests", "sessions_copy_delete", "post_monocal")
+    workspace = Path(__root__, "tests", "sessions_copy_delete", "post_monocal")
     copy_contents(original_workspace, workspace)
 
     controller = Controller(workspace_dir=workspace)
-    
-    # calibration requires a capture volume object which is composed of both a camera array, 
+
+    # calibration requires a capture volume object which is composed of both a camera array,
     # and a set of point estimates
     controller.load_camera_array()
 
@@ -30,7 +27,7 @@ def test_extrinsic_calibration():
         cam.rotation = None
         cam.translation = None
 
-    assert(not controller.camera_array.all_extrinsics_calibrated())
+    assert not controller.camera_array.all_extrinsics_calibrated()
 
     # with the charuco points tracked and saved out, the calibration can now proceed
     controller.calibrate_capture_volume()
@@ -40,19 +37,21 @@ def test_extrinsic_calibration():
         logger.info("waiting on camera array to finalize calibration...")
 
     logger.info(f"New Camera array is {controller.camera_array}")
-    assert(controller.camera_array.all_extrinsics_calibrated())
+    assert controller.camera_array.all_extrinsics_calibrated()
 
-def test_video_property_reader():
 
-    test_source = Path(__root__, "tests", "sessions", "prerecorded_calibration","calibration", "intrinsic", "port_1.mp4")
+def test_video_property_reader():
+    test_source = Path(
+        __root__, "tests", "sessions", "prerecorded_calibration", "calibration", "intrinsic", "port_1.mp4"
+    )
     logger.info(f"Testing with source file: {test_source}")
-    assert(test_source.exists())
+    assert test_source.exists()
     source_properties = read_video_properties(source_path=test_source)
-    assert(source_properties["frame_count"]==48)    
-    assert(source_properties["fps"]==6.0)    
-    assert(source_properties["size"]==(1280,720))
+    assert source_properties["frame_count"] == 48
+    assert source_properties["fps"] == 6.0
+    assert source_properties["size"] == (1280, 720)
 
-# if __name__ == "__main__":
-    # test_extrinsic_calibration()
-    # test_video_property_reader()
 
+if __name__ == "__main__":
+    test_extrinsic_calibration()
+    test_video_property_reader()
diff --git a/tests/test_export.py b/tests/test_export.py
index 2b0e1393..05e04e85 100644
--- a/tests/test_export.py
+++ b/tests/test_export.py
@@ -1,17 +1,17 @@
 # %%
 
-from caliscope.trackers.holistic.holistic_tracker import HolisticTracker
 from pathlib import Path
-from caliscope import __root__
-from caliscope.helper import copy_contents
-from caliscope.export import xyz_to_wide_labelled, xyz_to_trc
 
-import csv
 import pandas as pd
 
+from caliscope import __root__
+from caliscope.export import xyz_to_trc, xyz_to_wide_labelled
+from caliscope.helper import copy_contents
+from caliscope.trackers.holistic.holistic_tracker import HolisticTracker
+
+original_data_path = Path(__root__, "tests", "sessions", "4_cam_recording", "recording_1", "HOLISTIC")
+working_data_path = Path(__root__, "tests", "sessions_copy_delete", "4_cam_recording", "recording_1", "HOLISTIC")
 
-original_data_path = Path( __root__, "tests", "sessions","4_cam_recording","recording_1", "HOLISTIC")
-working_data_path = Path( __root__, "tests", "sessions_copy_delete","4_cam_recording","recording_1", "HOLISTIC")
 
 def test_export():
     copy_contents(original_data_path, working_data_path)
@@ -35,10 +35,10 @@ def test_export():
     trc_path = Path(xyz_csv_path.parent, f"{xyz_csv_path.stem}.trc")
     assert not trc_path.exists()
 
-    xyz_to_trc(xyz,tracker,time_history_path, target_path=trc_path)
+    xyz_to_trc(xyz, tracker, time_history_path, target_path=trc_path)
     assert trc_path.exists()
     # %%
 
+
 if __name__ == "__main__":
-    
-    test_export()
\ No newline at end of file
+    test_export()
diff --git a/tests/test_gap_fill.py b/tests/test_gap_fill.py
index 4881a69c..60d06831 100644
--- a/tests/test_gap_fill.py
+++ b/tests/test_gap_fill.py
@@ -1,16 +1,14 @@
-
-#%%
-import caliscope.logger
-
+# %%
+from pathlib import Path
 
 import pandas as pd
-import numpy as np
 
-from pathlib import Path
-from caliscope.trackers.tracker_enum import TrackerEnum
-from caliscope.post_processing.gap_filling import gap_fill_xy, gap_fill_xyz
+import caliscope.logger
 from caliscope import __root__
 from caliscope.helper import copy_contents
+from caliscope.post_processing.gap_filling import gap_fill_xy, gap_fill_xyz
+from caliscope.trackers.tracker_enum import TrackerEnum
+
 logger = caliscope.logger.get(__name__)
 
 original_recording_directory = Path(__root__, "tests", "reference", "base_data")
@@ -19,10 +17,10 @@
 recording_directory = Path(original_recording_directory.parent.parent, "reference_delete", "base_data")
 copy_contents(original_recording_directory, recording_directory)
 
-def test_gap_fill_xy():
 
+def test_gap_fill_xy():
     # Load the data
-    xy_all_base_path = Path(recording_directory,tracker_enum.name, f"xy_{tracker_enum.name}.csv")
+    xy_all_base_path = Path(recording_directory, tracker_enum.name, f"xy_{tracker_enum.name}.csv")
     logger.info(f"Reading in raw xy data located at {xy_all_base_path}")
     xy_all_base = pd.read_csv(xy_all_base_path)
     base_length = xy_all_base.shape[0]
@@ -36,10 +34,10 @@ def test_gap_fill_xy():
     assert base_length < filled_length
     assert xy_all_filled["gap_size"].max() > 0
 
-def test_gap_fill_xyz():
 
+def test_gap_fill_xyz():
     # Load the data
-    xyz_all_base_path = Path(recording_directory,tracker_enum.name, f"xyz_{tracker_enum.name}.csv")
+    xyz_all_base_path = Path(recording_directory, tracker_enum.name, f"xyz_{tracker_enum.name}.csv")
     logger.info(f"Reading in raw xy data located at {xyz_all_base_path}")
     xyz_all_base = pd.read_csv(xyz_all_base_path)
     base_length = xyz_all_base.shape[0]
@@ -53,7 +51,7 @@ def test_gap_fill_xyz():
     assert base_length < filled_length
     assert xyz_all_filled["gap_size"].max() > 0
 
+
 if __name__ == "__main__":
     test_gap_fill_xy()
     test_gap_fill_xyz()
-
diff --git a/tests/test_intrinsic_calibrator.py b/tests/test_intrinsic_calibrator.py
index 87c53f6b..d61ab20f 100644
--- a/tests/test_intrinsic_calibrator.py
+++ b/tests/test_intrinsic_calibrator.py
@@ -1,17 +1,17 @@
 from pathlib import Path
-import random    
 from queue import Queue
 from time import sleep
+
 import numpy as np
+
+import caliscope.logger
 from caliscope import __root__
-from caliscope.helper import copy_contents
 from caliscope.calibration.charuco import Charuco
-from caliscope.trackers.charuco_tracker import CharucoTracker
-from caliscope.recording.recorded_stream import RecordedStream
-from caliscope.cameras.camera_array import CameraData
-import caliscope.logger
-
 from caliscope.calibration.intrinsic_calibrator import IntrinsicCalibrator
+from caliscope.cameras.camera_array import CameraData
+from caliscope.helper import copy_contents
+from caliscope.recording.recorded_stream import RecordedStream
+from caliscope.trackers.charuco_tracker import CharucoTracker
 
 logger = caliscope.logger.get(__name__)
 
@@ -19,24 +19,16 @@
 def test_intrinsic_calibrator():
     # use a general video file with a charuco for convenience
     original_data_path = Path(__root__, "tests", "sessions", "4_cam_recording")
-    destination_path = Path(
-        __root__, "tests", "sessions_copy_delete", "4_cam_recording"
-    )
+    destination_path = Path(__root__, "tests", "sessions_copy_delete", "4_cam_recording")
     copy_contents(original_data_path, destination_path)
 
-    recording_directory = Path(
-        __root__, "tests", "sessions", "post_monocal", "calibration", "extrinsic"
-    )
+    recording_directory = Path(__root__, "tests", "sessions", "post_monocal", "calibration", "extrinsic")
 
-    charuco = Charuco(
-        4, 5, 11, 8.5, aruco_scale=0.75, square_size_overide_cm=5.25, inverted=True
-    )
+    charuco = Charuco(4, 5, 11, 8.5, aruco_scale=0.75, square_size_overide_cm=5.25, inverted=True)
 
     charuco_tracker = CharucoTracker(charuco)
 
-    stream = RecordedStream(
-        recording_directory, port=1, rotation_count=0, tracker=charuco_tracker
-    )
+    stream = RecordedStream(recording_directory, port=1, rotation_count=0, tracker=charuco_tracker)
 
     camera = CameraData(port=0, size=stream.size)
 
@@ -89,24 +81,16 @@ def test_intrinsic_calibrator():
 def test_autopopulate_data():
     # use a general video file with a charuco for convenience
     original_data_path = Path(__root__, "tests", "sessions", "4_cam_recording")
-    destination_path = Path(
-        __root__, "tests", "sessions_copy_delete", "4_cam_recording"
-    )
+    destination_path = Path(__root__, "tests", "sessions_copy_delete", "4_cam_recording")
     copy_contents(original_data_path, destination_path)
 
-    recording_directory = Path(
-        __root__, "tests", "sessions", "post_monocal", "calibration", "extrinsic"
-    )
+    recording_directory = Path(__root__, "tests", "sessions", "post_monocal", "calibration", "extrinsic")
 
-    charuco = Charuco(
-        4, 5, 11, 8.5, aruco_scale=0.75, square_size_overide_cm=5.25, inverted=True
-    )
+    charuco = Charuco(4, 5, 11, 8.5, aruco_scale=0.75, square_size_overide_cm=5.25, inverted=True)
 
     charuco_tracker = CharucoTracker(charuco)
 
-    stream = RecordedStream(
-        recording_directory, port=1, rotation_count=0, tracker=charuco_tracker
-    )
+    stream = RecordedStream(recording_directory, port=1, rotation_count=0, tracker=charuco_tracker)
 
     camera = CameraData(port=0, size=stream.size)
 
@@ -124,7 +108,7 @@ def test_autopopulate_data():
     stream.play_video()
     stream.pause()
 
-    packet = frame_q.get()  # pull off frame 0 to clear queue
+    _ = frame_q.get()  # pull off frame 0 to clear queue
 
     target_grid_count = 25
     wait_between = 3
@@ -137,19 +121,19 @@ def test_autopopulate_data():
 
     stream.jump_to(0)
     stream.unpause()
-    
+
     while intrinsic_calibrator.auto_store_data.is_set():
         actual_grid_count = len(intrinsic_calibrator.calibration_frame_indices)
         logger.info(f"waiting for data to populate...currently {actual_grid_count}")
-        
-        sleep(.5)
+
+        sleep(0.5)
 
     intrinsic_calibrator.backfill_calibration_frames()
     intrinsic_calibrator.calibrate_camera()
-    assert(camera.grid_count ==target_grid_count)
+    assert camera.grid_count == target_grid_count
     logger.info(f"Calibration complete: {camera}")
 
-if __name__ == "__main__":
 
+if __name__ == "__main__":
     test_intrinsic_calibrator()
     test_autopopulate_data()
diff --git a/tests/test_metarig_config_json.py b/tests/test_metarig_config_json.py
index 5b841804..6dffbe2b 100644
--- a/tests/test_metarig_config_json.py
+++ b/tests/test_metarig_config_json.py
@@ -1,19 +1,19 @@
-
-#%%
+# %%
 import json
-
-from caliscope import __root__
 from pathlib import Path
 
-from caliscope.trackers.tracker_enum import TrackerEnum
+import caliscope.logger
+from caliscope import __root__
 from caliscope.post_processing.blender_tools import generate_metarig_config
+from caliscope.trackers.tracker_enum import TrackerEnum
 
-import caliscope.logger
 logger = caliscope.logger.get(__name__)
+
+
 def test_metarig_config_generation():
-    xyz_csv_path = Path(__root__,"tests", "reference", "auto_rig_config_data", "xyz_HOLISTIC_OPENSIM_labelled.csv")
+    xyz_csv_path = Path(__root__, "tests", "reference", "auto_rig_config_data", "xyz_HOLISTIC_OPENSIM_labelled.csv")
     tracker_enum = TrackerEnum.HOLISTIC_OPENSIM
-    
+
     ######## code block for testing purposes  ######
     tracker = tracker_enum.value()
     # for testing purposes, need to make sure that this file is not there before proceeding
@@ -21,24 +21,22 @@ def test_metarig_config_generation():
     json_path.unlink(missing_ok=True)
     assert not json_path.exists()
     #################################################
-    
-    
-    generate_metarig_config(tracker_enum,xyz_csv_path)
 
+    generate_metarig_config(tracker_enum, xyz_csv_path)
 
     ######## very basic assertions on generated output  ###
-    with open(json_path,"r") as f:
-        check_autorig_config = json.load(f)    
-  
-    # make sure all measures are accounted for and sensible  
+    with open(json_path, "r") as f:
+        check_autorig_config = json.load(f)
+
+    # make sure all measures are accounted for and sensible
     for measure, points in tracker.metarig_symmetrical_measures.items():
         assert measure in check_autorig_config.keys()
-        assert type(check_autorig_config[measure]) == float
+        assert isinstance(check_autorig_config[measure], float)
 
     for measure, points in tracker.metarig_bilateral_measures.items():
         assert measure in check_autorig_config.keys()
-        assert type(check_autorig_config[measure]) == float
+        assert isinstance(check_autorig_config[measure], float)
 
 
 if __name__ == "__main__":
-    test_metarig_config_generation()
\ No newline at end of file
+    test_metarig_config_generation()
diff --git a/tests/test_motion_trial.py b/tests/test_motion_trial.py
index d6d509ff..55d89aa6 100644
--- a/tests/test_motion_trial.py
+++ b/tests/test_motion_trial.py
@@ -1,32 +1,33 @@
 from pathlib import Path
+
+import caliscope.logger
 from caliscope import __root__
 from caliscope.motion_trial import MotionTrial
 from caliscope.packets import XYZPacket
-import caliscope.logger
 
 logger = caliscope.logger.get(__name__)
 
+
 def test_motion_trial():
-    
-    test_csv = Path(__root__, "tests", "sessions", "4_cam_recording", "recording_1", "HOLISTIC_OPENSIM", "xyz_HOLISTIC_OPENSIM.csv")
+    test_csv = Path(
+        __root__, "tests", "sessions", "4_cam_recording", "recording_1", "HOLISTIC_OPENSIM", "xyz_HOLISTIC_OPENSIM.csv"
+    )
     motion_trial = MotionTrial(test_csv)
 
     # able to read in xyz packet
     xyz_packet_0 = motion_trial.get_xyz(0)
-    assert(isinstance(xyz_packet_0, XYZPacket))
-    assert(xyz_packet_0.point_xyz.shape[1]==3)
-    
+    assert isinstance(xyz_packet_0, XYZPacket)
+    assert xyz_packet_0.point_xyz.shape[1] == 3
+
     # able to read in tracker information
-    assert(motion_trial.tracker.name == "HOLISTIC_OPENSIM")
-    assert(xyz_packet_0.point_ids.shape[0] == xyz_packet_0.point_xyz.shape[0])
+    assert motion_trial.tracker.name == "HOLISTIC_OPENSIM"
+    assert xyz_packet_0.point_ids.shape[0] == xyz_packet_0.point_xyz.shape[0]
 
-    logger.info(motion_trial)     
+    logger.info(motion_trial)
 
     # todo:
     # motion trial has active frame that defaults to 0 or last read frame
 
+
 if __name__ == "__main__":
     test_motion_trial()
-     
-
-
diff --git a/tests/test_no_video_calibrate.py b/tests/test_no_video_calibrate.py
index 07c8323a..c11ce680 100644
--- a/tests/test_no_video_calibrate.py
+++ b/tests/test_no_video_calibrate.py
@@ -1,28 +1,17 @@
-
-from pathlib import Path
-from caliscope import __root__
-from caliscope.motion_trial import MotionTrial
-from caliscope.packets import XYZPacket
 import caliscope.logger
 
 logger = caliscope.logger.get(__name__)
 
+
 def test_no_video_calibrate():
     """
-    Saving out of video may be maxing system resources when high res/many cameras. 
+    Saving out of video may be maxing system resources when high res/many cameras.
     Allow user to toggle this off to free up resources
     """
-    
-    
+
     # copy over project to test
     pass
 
 
-
-
-
-
-
-
 if __name__ == "__main__":
-    pass
\ No newline at end of file
+    pass
diff --git a/tests/test_smoothing.py b/tests/test_smoothing.py
index c6a4792f..33c605cc 100644
--- a/tests/test_smoothing.py
+++ b/tests/test_smoothing.py
@@ -1,24 +1,20 @@
-
-import caliscope.logger
-
-logger = caliscope.logger.get(__name__)
-
 import sys
-from caliscope.configurator import Configurator
 from pathlib import Path
-from caliscope import __root__
+
 import pandas as pd
-import numpy as np
+from PySide6.QtWidgets import QApplication
 from scipy.stats import pearsonr
 
+import caliscope.logger
+from caliscope import __root__
+from caliscope.configurator import Configurator
+from caliscope.gui.vizualize.playback_triangulation_widget import PlaybackTriangulationWidget
+
 # specify a source directory (with recordings)
 from caliscope.helper import copy_contents
-import rtoml
-from PySide6.QtWidgets import QApplication
-from caliscope.gui.vizualize.playback_triangulation_widget import PlaybackTriangulationWidget
-from caliscope.post_processing.smoothing import _smooth_xy, smooth_xyz
-from caliscope import __root__
+from caliscope.post_processing.smoothing import smooth_xyz
 
+logger = caliscope.logger.get(__name__)
 original_base_data_directory = Path(__root__, "tests", "reference", "base_data")
 base_data_directory = Path(original_base_data_directory.parent.parent, "reference_delete", "base_data")
 copy_contents(original_base_data_directory, base_data_directory)
@@ -26,18 +22,17 @@
 xyz_path = Path(base_data_directory, "HOLISTIC_OPENSIM", "xyz_HOLISTIC_OPENSIM.csv")
 config = Configurator(base_data_directory)
 
-def test_smoothing_xyz():
 
+def test_smoothing_xyz():
     # Define your filter parameters
     order = 2
     # fs = config.get_fps_recording()  # sample rate, Hz
-    fs = 15 # the value originally stored in the config file
+    fs = 15  # the value originally stored in the config file
     # note that the cutoff must be < 0.5*(sampling rate, a.k.a. nyquist frequency)
     cutoff = 6  # desired cutoff frequency, Hz
 
-
     xyz = pd.read_csv(xyz_path)
-    xyz_smoothed = smooth_xyz(xyz, order,fs, cutoff)
+    xyz_smoothed = smooth_xyz(xyz, order, fs, cutoff)
 
     # save out the filterd data
     destination_path = Path(xyz_path.parent, xyz_path.stem + "_filtered.csv")
@@ -46,22 +41,27 @@ def test_smoothing_xyz():
 
     # Assertion 3: Value range (we'll check this for each of the coordinate columns)
     for coord in ["x_coord", "y_coord", "z_coord"]:
-        assert xyz_smoothed[coord].std() <= xyz[coord].std(), f"The standard deviation of the smoothed {coord} data should be less than the original data."
+        assert (
+            xyz_smoothed[coord].std() <= xyz[coord].std()
+        ), f"The standard deviation of the smoothed {coord} data should be less than the original data."
 
     # Assertion 4: Preservation of trends (again, we'll check for each coordinate)
     for coord in ["x_coord", "y_coord", "z_coord"]:
         correlation, _ = pearsonr(xyz[coord], xyz_smoothed[coord])
         logger.info(f"The correlation for {coord} is {correlation}")
-        assert correlation > 0.9, f"The correlation between the original and smoothed {coord} data should be close to 1."
+        assert (
+            correlation > 0.9
+        ), f"The correlation between the original and smoothed {coord} data should be close to 1."
+
 
 if __name__ == "__main__":
     test_smoothing_xyz()
-    
+
     app = QApplication(sys.argv)
 
     # load in the data for the playback
     camera_array = config.get_camera_array()
-    filtered_data_path =Path(base_data_directory, "HOLISTIC_OPENSIM", "xyz_HOLISTIC_OPENSIM_filtered.csv") 
+    filtered_data_path = Path(base_data_directory, "HOLISTIC_OPENSIM", "xyz_HOLISTIC_OPENSIM_filtered.csv")
     filtered_data = pd.read_csv(filtered_data_path)
 
     # create and show the playback widget
diff --git a/tests/test_stream.py b/tests/test_stream.py
index acce4f31..bfe11251 100644
--- a/tests/test_stream.py
+++ b/tests/test_stream.py
@@ -3,67 +3,65 @@
 from time import sleep
 
 import cv2
+
+import caliscope.logger
 from caliscope import __root__
 from caliscope.calibration.charuco import Charuco
-from caliscope.trackers.charuco_tracker import CharucoTracker
 from caliscope.recording.recorded_stream import RecordedStream
-
-import caliscope.logger
+from caliscope.trackers.charuco_tracker import CharucoTracker
 
 logger = caliscope.logger.get(__name__)
+
+
 def test_stream():
-    
-    recording_directory = Path(
-        __root__, "tests", "sessions", "post_monocal", "calibration", "extrinsic"
-    )
+    recording_directory = Path(__root__, "tests", "sessions", "post_monocal", "calibration", "extrinsic")
 
-    charuco = Charuco(
-        4, 5, 11, 8.5, aruco_scale=0.75, square_size_overide_cm=5.25, inverted=True
-    )
+    charuco = Charuco(4, 5, 11, 8.5, aruco_scale=0.75, square_size_overide_cm=5.25, inverted=True)
 
     charuco_tracker = CharucoTracker(charuco)
-    
-    stream  = RecordedStream(recording_directory,port=1,rotation_count=0, tracker=charuco_tracker, fps_target=6)
+
+    stream = RecordedStream(recording_directory, port=1, rotation_count=0, tracker=charuco_tracker, fps_target=6)
     frame_q = Queue()
     stream.subscribe(frame_q)
     stream.play_video()
     stream.pause()
-   
-    sleep(1)  
-    logger.info(f"Stream frame index is {stream.frame_index}") 
-    sleep(1)  
-    logger.info(f"Stream frame index is {stream.frame_index}") 
-    
+
+    sleep(1)
+    logger.info(f"Stream frame index is {stream.frame_index}")
+    sleep(1)
+    logger.info(f"Stream frame index is {stream.frame_index}")
+
     stream.unpause()
-    
+
     while True:
         frame_packet = frame_q.get()
-    
+
         if frame_packet.frame is None:
             break
-   
-        if stream.frame_index  == 10:
+
+        if stream.frame_index == 10:
             logger.info("Testing pause/unpause functionality")
             stream.pause()
-            sleep(.5)
+            sleep(0.5)
             test_index = stream.frame_index
-            sleep(.1)
+            sleep(0.5)
             # make sure that stream doesn't advance with pause
-            assert(test_index == stream.frame_index)
+            assert test_index == stream.frame_index
             stream.unpause()
 
         if stream.frame_index == 15:
             logger.info("Testing ability to jump forward")
             target_frame = 20
             stream.pause()
+            sleep(1)  # need to make sure fps_target wait plays out
             stream.jump_to(target_frame)
-            sleep(.2) # need to make sure fps_target wait plays out
-            assert(stream.frame_index == 20)
-           
-            logger.info(f"After attempting to jump to target frame {target_frame} ") 
+            sleep(1)  # need to make sure fps_target wait plays out
+            assert stream.frame_index == 21
+
+            logger.info(f"After attempting to jump to target frame {target_frame} ")
             current_frame = int(stream.capture.get(cv2.CAP_PROP_POS_FRAMES))
             logger.info(f"Current frame is now {current_frame}")
-            assert(current_frame == 20)
+            assert current_frame == 21
             stream.unpause()
 
         # cv2.imshow("Test", frame_packet.frame_with_points)
@@ -71,6 +69,6 @@ def test_stream():
         # if key == ord("q"):
         #     break
 
+
 if __name__ == "__main__":
     test_stream()
-    
diff --git a/tests/test_sync_stream_manager.py b/tests/test_sync_stream_manager.py
index 0953517f..086a10e7 100644
--- a/tests/test_sync_stream_manager.py
+++ b/tests/test_sync_stream_manager.py
@@ -1,19 +1,14 @@
-import caliscope.logger
+import time
+from pathlib import Path
 
 import pandas as pd
+
+import caliscope.logger
 from caliscope import __root__
-import shutil
-from pathlib import Path
-import time
 from caliscope.configurator import Configurator
 from caliscope.helper import copy_contents
-from caliscope.cameras.camera_array import CameraArray, CameraData
 from caliscope.synchronized_stream_manager import SynchronizedStreamManager
 from caliscope.trackers.charuco_tracker import CharucoTracker
-from caliscope.calibration.charuco import Charuco
-import shutil
-import pandas as pd
-import numpy as np
 
 logger = caliscope.logger.get(__name__)
 
@@ -21,13 +16,13 @@
 def assert_almost_equal(val1, val2, delta, msg):
     assert abs(val1 - val2) <= delta, msg
 
+
 def test_sync_stream_manager():
     original_workspace = Path(__root__, "tests", "sessions", "4_cam_recording")
     test_workspace = Path(__root__, "tests", "sessions_copy_delete", "4_cam_recording")
 
     copy_contents(original_workspace, test_workspace)
 
-
     config = Configurator(test_workspace)
     charuco = config.get_charuco()
     tracker = CharucoTracker(charuco)
@@ -39,7 +34,7 @@ def test_sync_stream_manager():
     # delete frame time history to assess success of imputed frame time method
     frame_history = Path(recording_dir, "frame_time_history.csv")
     frame_history.unlink()
-        
+
     sync_stream_manager = SynchronizedStreamManager(
         recording_dir=recording_dir,
         all_camera_data=camera_array.cameras,
@@ -49,29 +44,28 @@ def test_sync_stream_manager():
     # playback streams with high fps target to speed processing
     sync_stream_manager.process_streams(fps_target=100)
 
-
     # Load the gold standard and test CSV files
     gold_standard_df = pd.read_csv(Path(original_workspace, "calibration", "extrinsic", "xy.csv"))
-    test_data_path =  Path(test_workspace, "calibration", "extrinsic", "CHARUCO", "xy_CHARUCO.csv")
+    test_data_path = Path(test_workspace, "calibration", "extrinsic", "CHARUCO", "xy_CHARUCO.csv")
 
     while not test_data_path.exists():
         # wait for the tracked points to be created to compare
         logger.info("Waiting for ")
         time.sleep(1)
-    
+
     test_df = pd.read_csv(test_data_path)
     # Adjust sync_index in gold_standard_df to start at 1
-    gold_standard_df['sync_index'] -= (gold_standard_df['sync_index'].min() - 1)
+    gold_standard_df["sync_index"] -= gold_standard_df["sync_index"].min() - 1
 
     # Merge the dataframes on sync_index, port, point_id
-    merged_df = pd.merge(gold_standard_df, test_df, on=['sync_index', 'port', 'point_id'], suffixes=('_gold', '_test'))
+    merged_df = pd.merge(gold_standard_df, test_df, on=["sync_index", "port", "point_id"], suffixes=("_gold", "_test"))
 
     # Define pixel tolerance for img_loc_x and img_loc_y
     pixel_tolerance = 10
 
     # Calculate the absolute differences and average difference for each row
-    merged_df['x_diff'] = (merged_df['img_loc_x_gold'] - merged_df['img_loc_x_test']).abs()
-    merged_df['y_diff'] = (merged_df['img_loc_y_gold'] - merged_df['img_loc_y_test']).abs()
+    merged_df["x_diff"] = (merged_df["img_loc_x_gold"] - merged_df["img_loc_x_test"]).abs()
+    merged_df["y_diff"] = (merged_df["img_loc_y_gold"] - merged_df["img_loc_y_test"]).abs()
     mean_x_diff = merged_df["x_diff"].mean()
     assert abs(mean_x_diff) < pixel_tolerance
     mean_y_diff = merged_df["y_diff"].mean()
@@ -81,6 +75,5 @@ def test_sync_stream_manager():
     logger.info(f"Mean y difference is {mean_y_diff} pixels")
 
 
-    
 if __name__ == "__main__":
     test_sync_stream_manager()
diff --git a/tests/test_synchronizer.py b/tests/test_synchronizer.py
index 78fe98bf..5d71697a 100644
--- a/tests/test_synchronizer.py
+++ b/tests/test_synchronizer.py
@@ -1,16 +1,18 @@
-import caliscope.logger
+import shutil
+import time
+from pathlib import Path
 
 import pandas as pd
+
+import caliscope.logger
 from caliscope import __root__
-import shutil
-from pathlib import Path
-import time
 from caliscope.configurator import Configurator
 from caliscope.helper import copy_contents
 from caliscope.synchronized_stream_manager import SynchronizedStreamManager
 
 logger = caliscope.logger.get(__name__)
 
+
 def test_synchronizer():
     original_session_path = Path(__root__, "tests", "sessions", "4_cam_recording")
     session_path = Path(
@@ -24,9 +26,7 @@ def test_synchronizer():
         logger.info(f"Removing previously copied sessions at {session_path}")
         shutil.rmtree(session_path)
 
-    logger.info(
-        f"Copying over files from {original_session_path} to {session_path} for testing purposes"
-    )
+    logger.info(f"Copying over files from {original_session_path} to {session_path} for testing purposes")
     copy_contents(original_session_path, session_path)
 
     config = Configurator(session_path)
@@ -35,15 +35,11 @@ def test_synchronizer():
     recording_directory = Path(session_path, "recording_1")
 
     camera_array = config.get_camera_array()
-    stream_manager = SynchronizedStreamManager(
-        recording_dir=recording_directory, all_camera_data=camera_array.cameras
-    )
+    stream_manager = SynchronizedStreamManager(recording_dir=recording_directory, all_camera_data=camera_array.cameras)
 
     logger.info("Creating Synchronizer")
     stream_manager.process_streams(fps_target=100)
-    target_frame_time_path = Path(
-        recording_directory, "processed", "frame_time_history.csv"
-    )
+    target_frame_time_path = Path(recording_directory, "processed", "frame_time_history.csv")
 
     while not target_frame_time_path.exists():
         # recorder hasn't finished yet
diff --git a/tests/test_triangulator.py b/tests/test_triangulator.py
index efdbd4c0..9b2de212 100644
--- a/tests/test_triangulator.py
+++ b/tests/test_triangulator.py
@@ -1,35 +1,34 @@
-""""
+""" "
 NOTE: In addition to testing the real time triangulation, this code bases
-its final assertions on the values from the original bundle adjustment. 
-This allows a cross check for the triangulation function that is distinct from 
-the optimization in the bundle adjustmnent. 
+its final assertions on the values from the original bundle adjustment.
+This allows a cross check for the triangulation function that is distinct from
+the optimization in the bundle adjustmnent.
 
-After recent inclusion of distortion into the triangulation, the tolerance 
+After recent inclusion of distortion into the triangulation, the tolerance
 of the final averaged triangulated position improved from 1.5 cm to 6 mm.
 """
-import caliscope.logger
-
-from time import sleep
-
-from caliscope.cameras.synchronizer import Synchronizer
-from caliscope.triangulate.sync_packet_triangulator import SyncPacketTriangulator
-from caliscope.cameras.camera_array import CameraArray
-from caliscope.recording.recorded_stream import RecordedStream
-from caliscope.calibration.charuco import Charuco
-from caliscope.trackers.charuco_tracker import CharucoTracker
-from caliscope.configurator import Configurator
-from caliscope.helper import copy_contents
 
 import shutil
 from pathlib import Path
+from time import sleep
+
 import numpy as np
 import pandas as pd
+
+import caliscope.logger
 from caliscope import __root__
+from caliscope.calibration.charuco import Charuco
+from caliscope.cameras.camera_array import CameraArray
+from caliscope.cameras.synchronizer import Synchronizer
+from caliscope.configurator import Configurator
+from caliscope.helper import copy_contents
+from caliscope.recording.recorded_stream import RecordedStream
+from caliscope.trackers.charuco_tracker import CharucoTracker
+from caliscope.triangulate.sync_packet_triangulator import SyncPacketTriangulator
 
 logger = caliscope.logger.get(__name__)
 
 
-
 def test_triangulator():
     original_session = Path(__root__, "tests", "sessions", "post_optimization")
     test_session = Path(
@@ -43,7 +42,7 @@ def test_triangulator():
         shutil.rmtree(test_session)
 
     copy_contents(original_session, test_session)
-    
+
     config = Configurator(test_session)
     config.refresh_point_estimates_from_toml()
     # origin_sync_index = config.dict["capture_volume"]["origin_sync_index"]
@@ -53,21 +52,16 @@ def test_triangulator():
 
     camera_array: CameraArray = config.get_camera_array()
 
-
     logger.info("Creating RecordedStreamPool based on calibration recordings")
     recording_directory = Path(test_session, "calibration", "extrinsic")
-    
+
     streams = {}
     for port, camera in camera_array.cameras.items():
         rotation_count = camera.rotation_count
         streams[port] = RecordedStream(
-            recording_directory,
-            port,
-            rotation_count,
-            fps_target=100,
-            tracker=charuco_tracker
+            recording_directory, port, rotation_count, fps_target=100, tracker=charuco_tracker
         )
-    
+
     logger.info("Creating Synchronizer")
     syncr = Synchronizer(streams)
 
@@ -79,7 +73,7 @@ def test_triangulator():
         recording_directory=recording_directory,
         tracker_name=charuco_tracker.name,
     )
-    
+
     for port, stream in streams.items():
         stream.play_video()
 
@@ -112,6 +106,5 @@ def test_triangulator():
 
 
 if __name__ == "__main__":
-
     test_triangulator()
 # %%
diff --git a/tests/test_wireframe_builder.py b/tests/test_wireframe_builder.py
index 24f4ac24..724e30c0 100644
--- a/tests/test_wireframe_builder.py
+++ b/tests/test_wireframe_builder.py
@@ -1,45 +1,48 @@
 from pathlib import Path
-from caliscope.trackers.wireframe_builder import get_wireframe
-from caliscope import __root__
 
 import caliscope.logger
-from caliscope.tracker import WireFrameView, Segment
+from caliscope import __root__
+from caliscope.tracker import Segment, WireFrameView
 from caliscope.trackers.holistic.holistic_tracker import POINT_NAMES, HolisticTracker
+from caliscope.trackers.wireframe_builder import get_wireframe
+
 logger = caliscope.logger.get(__name__)
 
+
 def test_wireframe_builder():
     """
     Simple test to aid with development of integrating the wireframe
     """
 
-    test_path = Path(__root__,"caliscope","trackers","holistic","holistic_wireframe.toml")
+    test_path = Path(__root__, "caliscope", "trackers", "holistic", "holistic_wireframe.toml")
     logger.info(f"Testing wireframe build of {test_path}")
     wireframe = get_wireframe(test_path, point_names=POINT_NAMES)
-    
-    assert(isinstance(wireframe,WireFrameView))
+
+    assert isinstance(wireframe, WireFrameView)
 
     for segment in wireframe.segments:
-        assert(isinstance(segment,Segment))
+        assert isinstance(segment, Segment)
 
     logger.info(wireframe)
- 
+
+
 def test_holistic_wireframe():
     """
     making sure the integration with the tracker is working...
     at least not throwing an error
     """
-    
+
     tracker = HolisticTracker()
     wireframe = tracker.wireframe
 
-    assert(isinstance(wireframe,WireFrameView))
+    assert isinstance(wireframe, WireFrameView)
 
     for segment in wireframe.segments:
-        assert(isinstance(segment,Segment))
+        assert isinstance(segment, Segment)
 
     logger.info(wireframe)
 
+
 if __name__ == "__main__":
-    
     # test_wireframe_builder()
-    test_holistic_wireframe()
\ No newline at end of file
+    test_holistic_wireframe()
diff --git a/tests/test_xy_csv_process.py b/tests/test_xy_csv_process.py
index ecb259b5..f165e1fd 100644
--- a/tests/test_xy_csv_process.py
+++ b/tests/test_xy_csv_process.py
@@ -1,11 +1,10 @@
+from pathlib import Path
 
-import caliscope.logger
+import pandas as pd
 
-import sys
-from caliscope.configurator import Configurator
-from pathlib import Path
+import caliscope.logger
 from caliscope import __root__
-import pandas as pd
+from caliscope.configurator import Configurator
 
 # specify a source directory (with recordings)
 from caliscope.helper import copy_contents
@@ -18,9 +17,7 @@
 def test_xy_point_creation():
     # create a clean directory to start from
     session_path = Path(__root__, "tests", "sessions", "mediapipe_calibration_2_cam")
-    copy_session_path = Path(
-        __root__, "tests", "sessions_copy_delete", "mediapipe_calibration_2_cam"
-    )
+    copy_session_path = Path(__root__, "tests", "sessions_copy_delete", "mediapipe_calibration_2_cam")
     copy_contents(session_path, copy_session_path)
 
     # create inputs to processing pipeline function
@@ -61,9 +58,7 @@ def test_xy_point_creation():
 
     frame_times = pd.read_csv(Path(recording_path, "frame_time_history.csv"))
     sync_index_count = len(frame_times["sync_index"].unique())
-    logger.info(
-        f"Sync index count in frame history: {sync_index_count} in frame history"
-    )
+    logger.info(f"Sync index count in frame history: {sync_index_count} in frame history")
     logger.info(f"Max sync index: {xy_data['sync_index'].max()} in xy.csv")
 
     LEEWAY = 2  # sync indices that might not get copied over due to not enough frames
diff --git a/tests/test_xy_to_xyz.py b/tests/test_xy_to_xyz.py
index 0a3fa9d0..c31a4b6f 100644
--- a/tests/test_xy_to_xyz.py
+++ b/tests/test_xy_to_xyz.py
@@ -1,29 +1,34 @@
-import caliscope.logger
-
 import time
-import pandas as pd
 from pathlib import Path
+
+import pandas as pd
+
+import caliscope.logger
 from caliscope import __root__
 from caliscope.configurator import Configurator
+from caliscope.helper import copy_contents
+from caliscope.trackers.tracker_enum import TrackerEnum
+
 # from caliscope.post_processing.post_processor import PostProcessor
 from caliscope.triangulate.triangulation import triangulate_xy
 
-from caliscope.helper import copy_contents
-from caliscope.trackers.tracker_enum import TrackerEnum
 logger = caliscope.logger.get(__name__)
 
+
 def test_xy_to_xyz_postprocessing():
     # load in file of xy point data
     origin_data = Path(__root__, "tests", "sessions", "4_cam_recording")
-    working_data = Path(__root__,"tests", "sessions_copy_delete", "4_cam_recording_2") # create alternate test directory because running into permission errors when invoking pytest
-    
+    working_data = Path(
+        __root__, "tests", "sessions_copy_delete", "4_cam_recording_2"
+    )  # create alternate test directory because running into permission errors when invoking pytest
+
     copy_contents(origin_data, working_data)
 
     config = Configurator(working_data)
     recording_directory = Path(working_data, "recording_1")
     tracker_enum = TrackerEnum.HOLISTIC
 
-    xy_path = Path(recording_directory,tracker_enum.name, f"xy_{tracker_enum.name}.csv")
+    xy_path = Path(recording_directory, tracker_enum.name, f"xy_{tracker_enum.name}.csv")
     xy_data = pd.read_csv(xy_path)
 
     start = time.time()
@@ -33,7 +38,7 @@ def test_xy_to_xyz_postprocessing():
     # the method create_xyz uses it.
     camera_array = config.get_camera_array()
 
-    xyz_history = triangulate_xy(xy_data,camera_array) 
+    xyz_history = triangulate_xy(xy_data, camera_array)
     logger.info(f"ending triangulation at {time.time()}")
     stop = time.time()
     logger.info(f"Elapsed time is {stop-start}. Note that on first iteration, @jit functions will take longer")
@@ -51,18 +56,18 @@ def test_xy_to_xyz_postprocessing():
     )
 
     # Assert that coordinates are within expected bounds around the origin
-    min_x, max_x = -2, 2    
-    min_y, max_y = -2, 2    
-    min_z, max_z = -2, 4    
+    min_x, max_x = -2, 2
+    min_y, max_y = -2, 2
+    min_z, max_z = -2, 4
     for x, y, z in zip(xyz_history["x_coord"], xyz_history["y_coord"], xyz_history["z_coord"]):
         assert min_x <= x <= max_x
         assert min_y <= y <= max_y
         assert min_z <= z <= max_z
 
-
     output_path = Path(recording_directory, "xyz.csv")
     xyz_history = pd.DataFrame(xyz_history)
     xyz_history.to_csv(output_path)
 
+
 if __name__ == "__main__":
     test_xy_to_xyz_postprocessing()