Repository: mehta-lab/recOrder (language: python)

Issue:
Format with black
Automatic formatting of `.py` documents with `black`.

Did not modify the auto-generated `./recOrder/plugin/qtdesigner/recOrder_ui.py`.
Enforce consistent code formatting in development
**Problem**

Although we depend on the `black` formatter in the `[dev]` requirements, it is not currently consistently used, and there are unconventional formatting (wrt PEP 8) widespread in the code base.

**Proposed solution**

- [x] We should arrange a PR that formats the existing code. (Done: #229)
- [x] The contributors should be required to format their code with the `black` formatter we specify in the `[dev]` requirement before pushing to the repository. (#185)
- [ ] (Optionally) we can also [incorporate formatting formatting in our GItHub Actions workflow](https://black.readthedocs.io/en/stable/integrations/github_actions.html)..

**Example**

`black` can be executed from the command line if the user has the `[dev]` environment activated.
If you are using a modern IDE, formatting can also be done by selecting the `black` installed in their virtual environment as the formatter backend (VS Code: `^/⌘ ⇧  P` and type 'format document with...').


Discussion / hints:
# [Codecov](https://codecov.io/gh/mehta-lab/recOrder/pull/179?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab) Report
> Merging [#179](https://codecov.io/gh/mehta-lab/recOrder/pull/179?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab) (543f06a) into [main](https://codecov.io/gh/mehta-lab/recOrder/commit/2c6eb2de379ab123ac6eeb8409a9c3d4c3bb3eb1?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab) (2c6eb2d) will **decrease** coverage by `0.04%`.
> The diff coverage is `21.49%`.

```diff
@@            Coverage Diff             @@
##             main     #179      +/-   ##
==========================================
- Coverage   11.21%   11.16%   -0.05%     
==========================================
  Files          45       45              
  Lines        5984     6010      +26     
==========================================
  Hits          671      671              
- Misses       5313     5339      +26     
```


| [Impacted Files](https://codecov.io/gh/mehta-lab/recOrder/pull/179?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab) | Coverage Δ | |
|---|---|---|
| [recOrder/acq/acq\_functions.py](https://codecov.io/gh/mehta-lab/recOrder/pull/179/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab#diff-cmVjT3JkZXIvYWNxL2FjcV9mdW5jdGlvbnMucHk=) | `0.00% <0.00%> (ø)` | |
| [recOrder/calib/Calibration.py](https://codecov.io/gh/mehta-lab/recOrder/pull/179/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab#diff-cmVjT3JkZXIvY2FsaWIvQ2FsaWJyYXRpb24ucHk=) | `0.00% <0.00%> (ø)` | |
| [recOrder/calib/Optimization.py](https://codecov.io/gh/mehta-lab/recOrder/pull/179/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab#diff-cmVjT3JkZXIvY2FsaWIvT3B0aW1pemF0aW9uLnB5) | `0.00% <0.00%> (ø)` | |
| [recOrder/compute/fluorescence\_compute.py](https://codecov.io/gh/mehta-lab/recOrder/pull/179/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab#diff-cmVjT3JkZXIvY29tcHV0ZS9mbHVvcmVzY2VuY2VfY29tcHV0ZS5weQ==) | `0.00% <0.00%> (ø)` | |
| [recOrder/compute/qlipp\_compute.py](https://codecov.io/gh/mehta-lab/recOrder/pull/179/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab#diff-cmVjT3JkZXIvY29tcHV0ZS9xbGlwcF9jb21wdXRlLnB5) | `0.00% <0.00%> (ø)` | |
| [recOrder/io/\_\_init\_\_.py](https://codecov.io/gh/mehta-lab/recOrder/pull/179/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab#diff-cmVjT3JkZXIvaW8vX19pbml0X18ucHk=) | `0.00% <0.00%> (ø)` | |
| [recOrder/io/\_reader.py](https://codecov.io/gh/mehta-lab/recOrder/pull/179/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab#diff-cmVjT3JkZXIvaW8vX3JlYWRlci5weQ==) | `0.00% <0.00%> (ø)` | |
| [recOrder/io/config\_reader.py](https://codecov.io/gh/mehta-lab/recOrder/pull/179/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab#diff-cmVjT3JkZXIvaW8vY29uZmlnX3JlYWRlci5weQ==) | `0.00% <0.00%> (ø)` | |
| [recOrder/io/core\_functions.py](https://codecov.io/gh/mehta-lab/recOrder/pull/179/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab#diff-cmVjT3JkZXIvaW8vY29yZV9mdW5jdGlvbnMucHk=) | `0.00% <0.00%> (ø)` | |
| [recOrder/io/metadata\_reader.py](https://codecov.io/gh/mehta-lab/recOrder/pull/179/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab#diff-cmVjT3JkZXIvaW8vbWV0YWRhdGFfcmVhZGVyLnB5) | `0.00% <0.00%> (ø)` | |
| ... and [31 more](https://codecov.io/gh/mehta-lab/recOrder/pull/179/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab) | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mehta-lab)

Preview page for your plugin is ready here:
https://preview.napari-hub.org/mehta-lab/recOrder/179
_Updated: 2022-09-24T00:17:29.595624_
'Initial formatting' is done manually here to break up the process into commits each modifying a single submodule for easier bug-fix traceback. This should not be necessary given the reliability of `black`, and is only performed out of an abundance of precaution. We should consider [enforcing formatting in our GItHub Actions workflow](https://black.readthedocs.io/en/stable/integrations/github_actions.html).
This PR will start to address #176. 
@talonchandler I think we should try to merge this relatively soon to avoid more conflicts.
Roger...I just took a quick flip through and highlighted some of the points that are really bizarre. 

Sorry I let this slip. Can you merge main into this branch, reformat, then I'll test Monday morning?
Fixed two typos I spotted in my sift through the changes. 
This PR is getting increasingly cluttered with conflicts now. I'm tempted to close it and open a new one following [instructions here](https://black.readthedocs.io/en/stable/guides/introducing_black_to_your_project.html#avoiding-ruining-git-blame). Any suggestions @talonchandler?
I'm very in favor of preserving git-blame info if possible (I use this info for context quite often). 

How about we do this on Wednesday (I just sent an invite for hummingbird)?
[GitHub's doc on formatter & `git blame`](https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view)
@ziw-liu and I are closing together. We will revisit black formatting after release.
Another issue to also think about is enforcing consistent Markdown documents with a linter, e.g. this one that is available as both a [GitHub Action](https://github.com/marketplace/actions/markdownlint-cli2-action) and an [editor plugin](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint).

Fix patch:
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 00000000..31e202a2
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,4 @@
+# .git-blame-ignore-revs
+# created as described in: https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view
+# black-format all `.py` files except recorder_ui.py
+958af2070cfb32397e7b7e8bfa7d022ec10b67af
\ No newline at end of file
diff --git a/docs/development-guide.md b/docs/development-guide.md
index 0f1460c8..c45d9bda 100644
--- a/docs/development-guide.md
+++ b/docs/development-guide.md
@@ -84,4 +84,14 @@ pyuic5 -x recOrder_ui.ui -o recOrder_ui.py
 ```
 Note: `pyuic5` is installed alongside `PyQt5`, so you can expect to find it installed in your `recOrder` conda environement. 
 
-Note: although much of the GUI is specified in the generated `recOrder_ui.py` file, the `main_widget.py` file makes extensive modifications to the GUI. 
\ No newline at end of file
+Note: although much of the GUI is specified in the generated `recOrder_ui.py` file, the `main_widget.py` file makes extensive modifications to the GUI.
+
+## Make `git blame` ignore formatting commits
+**Note:** `git --version` must be `>=2.23` to use this feature.
+
+If you would like `git blame` to ignore formatting commits, run this line: 
+```sh
+ git config --global blame.ignoreRevsFile .git-blame-ignore-revs
+```
+
+The `\.git-blame-ignore-revs` file contains a list of commit hashes corresponding to formatting commits. If you make a formatting commit, please add the commit's hash to this file.
\ No newline at end of file
diff --git a/recOrder/__init__.py b/recOrder/__init__.py
index 6d76432a..f9ca19c7 100644
--- a/recOrder/__init__.py
+++ b/recOrder/__init__.py
@@ -1,4 +1,4 @@
-#todo: format overall init
+# todo: format overall init
 
 # from .plugin.widget.napari_plugin_entry_point import napari_experimental_provide_dock_widget
-# name = "recOrder"
\ No newline at end of file
+# name = "recOrder"
diff --git a/recOrder/acq/acq_functions.py b/recOrder/acq/acq_functions.py
index cc60e730..80219ca3 100644
--- a/recOrder/acq/acq_functions.py
+++ b/recOrder/acq/acq_functions.py
@@ -6,8 +6,19 @@
 import time
 import glob
 
-def generate_acq_settings(mm, channel_group, channels=None, zstart=None, zend=None, zstep=None,
-                          save_dir=None, prefix=None, keep_shutter_open_channels=False, keep_shutter_open_slices=False):
+
+def generate_acq_settings(
+    mm,
+    channel_group,
+    channels=None,
+    zstart=None,
+    zend=None,
+    zstep=None,
+    save_dir=None,
+    prefix=None,
+    keep_shutter_open_channels=False,
+    keep_shutter_open_slices=False,
+):
     """
     This function generates a json file specific to the micromanager SequenceSettings.
     It has default parameters for a multi-channels z-stack acquisition but does not yet
@@ -46,58 +57,67 @@ def generate_acq_settings(mm, channel_group, channels=None, zstart=None, zend=No
         do_z = False
 
     # Structure of the channel properties
-    channel_dict = {'channelGroup': channel_group,
-                    'config': None,
-                    'exposure': None,
-                    'zOffset': 0,
-                    'doZStack': do_z,
-                    'color': {'value': -16747854, 'falpha': 0.0},
-                    'skipFactorFrame': 0,
-                    'useChannel': True if channels else False}
+    channel_dict = {
+        "channelGroup": channel_group,
+        "config": None,
+        "exposure": None,
+        "zOffset": 0,
+        "doZStack": do_z,
+        "color": {"value": -16747854, "falpha": 0.0},
+        "skipFactorFrame": 0,
+        "useChannel": True if channels else False,
+    }
 
     channel_list = None
     if channels:
         # Append all the channels with their current exposure settings
         channel_list = []
         for chan in channels:
-            #todo: think about how to deal with missing exposure
-            exposure = app.getChannelExposureTime(channel_group, chan, 10) # sets exposure to 10 if not found
+            # todo: think about how to deal with missing exposure
+            exposure = app.getChannelExposureTime(
+                channel_group, chan, 10
+            )  # sets exposure to 10 if not found
             channel = channel_dict.copy()
-            channel['config'] = chan
-            channel['exposure'] = exposure
+            channel["config"] = chan
+            channel["exposure"] = exposure
 
             channel_list.append(channel)
 
     # set other parameters
-    original_json['numFrames'] = 1
-    original_json['intervalMs'] = 0
-    original_json['relativeZSlice'] = True
-    original_json['slicesFirst'] = True
-    original_json['timeFirst'] = False
-    original_json['keepShutterOpenSlices'] = keep_shutter_open_slices
-    original_json['keepShutterOpenChannels'] = keep_shutter_open_channels
-    original_json['useAutofocus'] = False
-    original_json['saveMode'] = 'MULTIPAGE_TIFF'
-    original_json['save'] = True if save_dir else False
-    original_json['root'] = save_dir if save_dir else ''
-    original_json['prefix'] = prefix if prefix else 'Untitled'
-    original_json['channels'] = channel_list
-    original_json['zReference'] = 0.0
-    original_json['channelGroup'] = channel_group
-    original_json['usePositionList'] = False
-    original_json['shouldDisplayImages'] = True
-    original_json['useSlices'] = do_z
-    original_json['useFrames'] = False
-    original_json['useChannels'] = True if channels else False
-    original_json['slices'] = list(np.arange(float(zstart), float(zend+zstep), float(zstep))) if zstart else []
-    original_json['sliceZStepUm'] = zstep
-    original_json['sliceZBottomUm'] = zstart
-    original_json['sliceZTopUm'] = zend
-    original_json['acqOrderMode'] = 1
+    original_json["numFrames"] = 1
+    original_json["intervalMs"] = 0
+    original_json["relativeZSlice"] = True
+    original_json["slicesFirst"] = True
+    original_json["timeFirst"] = False
+    original_json["keepShutterOpenSlices"] = keep_shutter_open_slices
+    original_json["keepShutterOpenChannels"] = keep_shutter_open_channels
+    original_json["useAutofocus"] = False
+    original_json["saveMode"] = "MULTIPAGE_TIFF"
+    original_json["save"] = True if save_dir else False
+    original_json["root"] = save_dir if save_dir else ""
+    original_json["prefix"] = prefix if prefix else "Untitled"
+    original_json["channels"] = channel_list
+    original_json["zReference"] = 0.0
+    original_json["channelGroup"] = channel_group
+    original_json["usePositionList"] = False
+    original_json["shouldDisplayImages"] = True
+    original_json["useSlices"] = do_z
+    original_json["useFrames"] = False
+    original_json["useChannels"] = True if channels else False
+    original_json["slices"] = (
+        list(np.arange(float(zstart), float(zend + zstep), float(zstep)))
+        if zstart
+        else []
+    )
+    original_json["sliceZStepUm"] = zstep
+    original_json["sliceZBottomUm"] = zstart
+    original_json["sliceZTopUm"] = zend
+    original_json["acqOrderMode"] = 1
 
     return original_json
 
-def acquire_from_settings(mm, settings, grab_images = True):
+
+def acquire_from_settings(mm, settings, grab_images=True):
     """
     Function to acquire an MDA acquisition with the native MM MDA Engine.
     Assumes single position acquisition.
@@ -121,17 +141,20 @@ def acquire_from_settings(mm, settings, grab_images = True):
 
     time.sleep(3)
 
-    #TODO: speed improvements in reading the data with pycromanager acquisition?
+    # TODO: speed improvements in reading the data with pycromanager acquisition?
     if grab_images:
         # get the most recent acquisition if multiple
-        path = os.path.join(settings['root'], settings['prefix'])
-        files = glob.glob(path+'*')
-        index = max([int(x.split(path + '_')[1]) for x in files])
+        path = os.path.join(settings["root"], settings["prefix"])
+        files = glob.glob(path + "*")
+        index = max([int(x.split(path + "_")[1]) for x in files])
 
-        reader = WaveorderReader(path+f'_{index}', 'ometiff', extract_data=True)
+        reader = WaveorderReader(
+            path + f"_{index}", "ometiff", extract_data=True
+        )
 
         return reader.get_array(0)
 
+
 def acquire_2D(mm, mmc, scheme, snap_manager=None):
     """
     Acquire a 2D stack with pycromanager (data transfer over ZMQ) given the acquisition scheme.
@@ -152,20 +175,20 @@ def acquire_2D(mm, mmc, scheme, snap_manager=None):
     if not snap_manager:
         snap_manager = mm.getSnapLiveManager()
 
-    set_lc_state(mmc, 'State0')
+    set_lc_state(mmc, "State0")
     state0 = snap_and_get_image(snap_manager)
 
-    set_lc_state(mmc, 'State1')
+    set_lc_state(mmc, "State1")
     state1 = snap_and_get_image(snap_manager)
 
-    set_lc_state(mmc, 'State2')
+    set_lc_state(mmc, "State2")
     state2 = snap_and_get_image(snap_manager)
 
-    set_lc_state(mmc, 'State3')
+    set_lc_state(mmc, "State3")
     state3 = snap_and_get_image(snap_manager)
 
-    if scheme == '5-State':
-        set_lc_state(mmc, 'State4')
+    if scheme == "5-State":
+        set_lc_state(mmc, "State4")
         state4 = snap_and_get_image(snap_manager)
         return np.asarray([state0, state1, state2, state3, state4])
 
@@ -198,12 +221,14 @@ def acquire_3D(mm, mmc, scheme, z_start, z_end, z_step, snap_manager=None):
 
     stage = mmc.getFocusDevice()
     current_z = mmc.getPosition(stage)
-    n_channels = 4 if scheme == '4-State' else 5
+    n_channels = 4 if scheme == "4-State" else 5
     stack = []
     for c in range(n_channels):
-        set_lc_state(mmc, f'State{c}')
+        set_lc_state(mmc, f"State{c}")
         z_stack = []
-        for z in np.arange(current_z+z_start, current_z+z_end+z_step, z_step):
+        for z in np.arange(
+            current_z + z_start, current_z + z_end + z_step, z_step
+        ):
             mmc.setPosition(stage, z)
             z_stack.append(snap_and_get_image(snap_manager))
 
diff --git a/recOrder/calib/Calibration.py b/recOrder/calib/Calibration.py
index 658ea7a2..7490e831 100644
--- a/recOrder/calib/Calibration.py
+++ b/recOrder/calib/Calibration.py
@@ -18,14 +18,22 @@
 from datetime import datetime
 from importlib_metadata import version
 
-LC_DEVICE_NAME = 'MeadowlarkLcOpenSource'
-
-
-class QLIPP_Calibration():
-
-    def __init__(self, mmc, mm, group='Channel', lc_control_mode='MM-Retardance', interp_method='schnoor_fit',
-                 wavelength=532, optimization='min_scalar', print_details=True):
-        '''
+LC_DEVICE_NAME = "MeadowlarkLcOpenSource"
+
+
+class QLIPP_Calibration:
+    def __init__(
+        self,
+        mmc,
+        mm,
+        group="Channel",
+        lc_control_mode="MM-Retardance",
+        interp_method="schnoor_fit",
+        wavelength=532,
+        optimization="min_scalar",
+        print_details=True,
+    ):
+        """
 
         Parameters
         ----------
@@ -54,7 +62,7 @@ def __init__(self, mmc, mm, group='Channel', lc_control_mode='MM-Retardance', in
             LC retardance optimization method, 'min_scalar' (default) or 'brent'
         print_details : bool
             Set verbose option
-        '''
+        """
 
         # Micromanager API
         self.mm = mm
@@ -62,46 +70,70 @@ def __init__(self, mmc, mm, group='Channel', lc_control_mode='MM-Retardance', in
         self.snap_manager = mm.getSnapLiveManager()
 
         # Meadowlark LC Device Adapter Property Names
-        self.PROPERTIES = {'LCA': (LC_DEVICE_NAME, 'Retardance LC-A [in waves]'),
-                           'LCB': (LC_DEVICE_NAME, 'Retardance LC-B [in waves]'),
-                           'LCA-Voltage': (LC_DEVICE_NAME, 'Voltage (V) LC-A'),
-                           'LCB-Voltage': (LC_DEVICE_NAME, 'Voltage (V) LC-B'),
-                           'LCA-DAC': ('TS_DAC01', 'Volts'),
-                           'LCB-DAC': ('TS_DAC02', 'Volts'),
-                           'State0': (LC_DEVICE_NAME, 'Pal. elem. 00; enter 0 to define; 1 to activate'),
-                           'State1': (LC_DEVICE_NAME, 'Pal. elem. 01; enter 0 to define; 1 to activate'),
-                           'State2': (LC_DEVICE_NAME, 'Pal. elem. 02; enter 0 to define; 1 to activate'),
-                           'State3': (LC_DEVICE_NAME, 'Pal. elem. 03; enter 0 to define; 1 to activate'),
-                           'State4': (LC_DEVICE_NAME, 'Pal. elem. 04; enter 0 to define; 1 to activate')
-                           }
+        self.PROPERTIES = {
+            "LCA": (LC_DEVICE_NAME, "Retardance LC-A [in waves]"),
+            "LCB": (LC_DEVICE_NAME, "Retardance LC-B [in waves]"),
+            "LCA-Voltage": (LC_DEVICE_NAME, "Voltage (V) LC-A"),
+            "LCB-Voltage": (LC_DEVICE_NAME, "Voltage (V) LC-B"),
+            "LCA-DAC": ("TS_DAC01", "Volts"),
+            "LCB-DAC": ("TS_DAC02", "Volts"),
+            "State0": (
+                LC_DEVICE_NAME,
+                "Pal. elem. 00; enter 0 to define; 1 to activate",
+            ),
+            "State1": (
+                LC_DEVICE_NAME,
+                "Pal. elem. 01; enter 0 to define; 1 to activate",
+            ),
+            "State2": (
+                LC_DEVICE_NAME,
+                "Pal. elem. 02; enter 0 to define; 1 to activate",
+            ),
+            "State3": (
+                LC_DEVICE_NAME,
+                "Pal. elem. 03; enter 0 to define; 1 to activate",
+            ),
+            "State4": (
+                LC_DEVICE_NAME,
+                "Pal. elem. 04; enter 0 to define; 1 to activate",
+            ),
+        }
         self.group = group
 
         # GUI Emitter
         self.intensity_emitter = MockEmitter()
         self.plot_sequence_emitter = MockEmitter()
 
-        #Set Mode
+        # Set Mode
         # TODO: make sure LC or TriggerScope are loaded in the respective modes
-        allowed_modes = ['MM-Retardance', 'MM-Voltage', 'DAC']
-        assert lc_control_mode in allowed_modes, f'LC control mode must be one of {allowed_modes}'
+        allowed_modes = ["MM-Retardance", "MM-Voltage", "DAC"]
+        assert (
+            lc_control_mode in allowed_modes
+        ), f"LC control mode must be one of {allowed_modes}"
         self.mode = lc_control_mode
         self.LC_DAC_conversion = 4  # convert between the input range of LCs (0-20V) and the output range of the DAC (0-5V)
 
         # Initialize calibration class
-        allowed_interp_methods = ['schnoor_fit', 'linear']
-        assert interp_method in allowed_interp_methods,\
-            f'LC calibration data interpolation method must be one of {allowed_interp_methods}'
-        dir_path = mmc.getDeviceAdapterSearchPaths().get(0) # MM device adapter directory
-        self.calib = CalibrationData(os.path.join(dir_path, 'mmgr_dal_MeadowlarkLC.csv'), interp_method=interp_method,
-                                     wavelength=wavelength)
+        allowed_interp_methods = ["schnoor_fit", "linear"]
+        assert (
+            interp_method in allowed_interp_methods
+        ), f"LC calibration data interpolation method must be one of {allowed_interp_methods}"
+        dir_path = mmc.getDeviceAdapterSearchPaths().get(
+            0
+        )  # MM device adapter directory
+        self.calib = CalibrationData(
+            os.path.join(dir_path, "mmgr_dal_MeadowlarkLC.csv"),
+            interp_method=interp_method,
+            wavelength=wavelength,
+        )
 
         # Optimizer
-        if optimization == 'min_scalar':
+        if optimization == "min_scalar":
             self.optimizer = MinScalarOptimizer(self)
-        elif optimization == 'brent':
+        elif optimization == "brent":
             self.optimizer = BrentOptimizer(self)
         else:
-            raise ModuleNotFoundError(f'No optimizer named {optimization}')
+            raise ModuleNotFoundError(f"No optimizer named {optimization}")
 
         # User / Calculated Parameters
         self.swing = None
@@ -111,7 +143,7 @@ def __init__(self, mmc, mm, group='Channel', lc_control_mode='MM-Retardance', in
         self.ROI = None
         self.ratio = 1.793
         self.print_details = print_details
-        self.calib_scheme = '4-State'
+        self.calib_scheme = "4-State"
 
         # LC States
         self.lca_ext = None
@@ -151,8 +183,8 @@ def __init__(self, mmc, mm, group='Channel', lc_control_mode='MM-Retardance', in
         self._shutter_state = None
 
     def set_dacs(self, lca_dac, lcb_dac):
-        self.PROPERTIES['LCA-DAC'] = (f'TS_{lca_dac}', 'Volts')
-        self.PROPERTIES['LCB-DAC'] = (f'TS_{lcb_dac}', 'Volts')
+        self.PROPERTIES["LCA-DAC"] = (f"TS_{lca_dac}", "Volts")
+        self.PROPERTIES["LCB-DAC"] = (f"TS_{lcb_dac}", "Volts")
 
     def set_wavelength(self, wavelength):
         self.calib.set_wavelength(wavelength)
@@ -174,15 +206,15 @@ def set_lc(self, retardance, LC: str):
 
         """
 
-        if self.mode == 'MM-Retardance':
-            set_lc_waves(self.mmc, self.PROPERTIES[f'{LC}'], retardance)
-        elif self.mode == 'MM-Voltage':
+        if self.mode == "MM-Retardance":
+            set_lc_waves(self.mmc, self.PROPERTIES[f"{LC}"], retardance)
+        elif self.mode == "MM-Voltage":
             volts = self.calib.get_voltage(retardance)
-            set_lc_voltage(self.mmc, self.PROPERTIES[f'{LC}-Voltage'], volts)
-        elif self.mode == 'DAC':
+            set_lc_voltage(self.mmc, self.PROPERTIES[f"{LC}-Voltage"], volts)
+        elif self.mode == "DAC":
             volts = self.calib.get_voltage(retardance)
             dac_volts = volts / self.LC_DAC_conversion
-            set_lc_daq(self.mmc, self.PROPERTIES[f'{LC}-DAC'], dac_volts)
+            set_lc_daq(self.mmc, self.PROPERTIES[f"{LC}-DAC"], dac_volts)
 
     def get_lc(self, LC: str):
         """
@@ -198,13 +230,15 @@ def get_lc(self, LC: str):
             LC retardance in waves
         """
 
-        if self.mode == 'MM-Retardance':
-            retardance = get_lc(self.mmc, self.PROPERTIES[f'{LC}'])
-        elif self.mode == 'MM-Voltage':
-            volts = get_lc(self.mmc, self.PROPERTIES[f'{LC}-Voltage'])  # returned value is in volts
+        if self.mode == "MM-Retardance":
+            retardance = get_lc(self.mmc, self.PROPERTIES[f"{LC}"])
+        elif self.mode == "MM-Voltage":
+            volts = get_lc(
+                self.mmc, self.PROPERTIES[f"{LC}-Voltage"]
+            )  # returned value is in volts
             retardance = self.calib.get_retardance(volts)
-        elif self.mode == 'DAC':
-            dac_volts = get_lc(self.mmc, self.PROPERTIES[f'{LC}-DAC'])
+        elif self.mode == "DAC":
+            dac_volts = get_lc(self.mmc, self.PROPERTIES[f"{LC}-DAC"])
             volts = dac_volts * self.LC_DAC_conversion
             retardance = self.calib.get_retardance(volts)
 
@@ -228,20 +262,37 @@ def define_lc_state(self, state, lca_retardance, lcb_retardance):
 
         """
 
-        if self.mode == 'MM-Retardance':
-            self.set_lc(lca_retardance, 'LCA')
-            self.set_lc(lcb_retardance, 'LCB')
+        if self.mode == "MM-Retardance":
+            self.set_lc(lca_retardance, "LCA")
+            self.set_lc(lcb_retardance, "LCB")
             define_meadowlark_state(self.mmc, self.PROPERTIES[state])
-        elif self.mode == 'DAC':
-            lca_volts = self.calib.get_voltage(lca_retardance) / self.LC_DAC_conversion
-            lcb_volts = self.calib.get_voltage(lcb_retardance) / self.LC_DAC_conversion
-            define_config_state(self.mmc, self.group, state,
-                                [self.PROPERTIES['LCA-DAC'], self.PROPERTIES['LCB-DAC']], [lca_volts, lcb_volts])
-        elif self.mode == 'MM-Voltage':
+        elif self.mode == "DAC":
+            lca_volts = (
+                self.calib.get_voltage(lca_retardance) / self.LC_DAC_conversion
+            )
+            lcb_volts = (
+                self.calib.get_voltage(lcb_retardance) / self.LC_DAC_conversion
+            )
+            define_config_state(
+                self.mmc,
+                self.group,
+                state,
+                [self.PROPERTIES["LCA-DAC"], self.PROPERTIES["LCB-DAC"]],
+                [lca_volts, lcb_volts],
+            )
+        elif self.mode == "MM-Voltage":
             lca_volts = self.calib.get_voltage(lca_retardance)
             lcb_volts = self.calib.get_voltage(lcb_retardance)
-            define_config_state(self.mmc, self.group, state,
-                                [self.PROPERTIES['LCA-Voltage'], self.PROPERTIES['LCB-Voltage']], [lca_volts, lcb_volts])
+            define_config_state(
+                self.mmc,
+                self.group,
+                state,
+                [
+                    self.PROPERTIES["LCA-Voltage"],
+                    self.PROPERTIES["LCB-Voltage"],
+                ],
+                [lca_volts, lcb_volts],
+            )
 
     def opt_lc(self, x, device_property, reference, normalize=False):
 
@@ -259,8 +310,8 @@ def opt_lc(self, x, device_property, reference, normalize=False):
             val = (mean - min_) / (max_ - min_)
             ref = (reference - min_) / (max_ - min_)
 
-            logging.debug(f'LC-Value: {x}')
-            logging.debug(f'F-Value:{val - ref}\n')
+            logging.debug(f"LC-Value: {x}")
+            logging.debug(f"F-Value:{val - ref}\n")
             return val - ref
 
         else:
@@ -275,11 +326,11 @@ def opt_lc_cons(self, x, device_property, reference, mode):
         self.set_lc(x, device_property)
         swing = (self.lca_ext - x) * self.ratio
 
-        if mode == '60':
-            self.set_lc(self.lcb_ext + swing, 'LCB')
+        if mode == "60":
+            self.set_lc(self.lcb_ext + swing, "LCB")
 
-        if mode == '120':
-            self.set_lc(self.lcb_ext - swing, 'LCB')
+        if mode == "120":
+            self.set_lc(self.lcb_ext - swing, "LCB")
 
         mean = snap_and_average(self.snap_manager)
         logging.debug(str(mean))
@@ -325,8 +376,8 @@ def opt_lc_grid(self, a_min, a_max, b_min, b_max, step):
         for lca in np.arange(a_min, a_max, step):
             for lcb in np.arange(b_min, b_max, step):
 
-                self.set_lc(lca, 'LCA')
-                self.set_lc(lcb, 'LCB')
+                self.set_lc(lca, "LCA")
+                self.set_lc(lcb, "LCB")
 
                 # current_int = np.mean(snap_image(calib.mmc))
                 current_int = snap_and_average(self.snap_manager)
@@ -336,7 +387,10 @@ def opt_lc_grid(self, a_min, a_max, b_min, b_max, step):
                     better_lca = lca
                     better_lcb = lcb
                     min_int = current_int
-                    logging.debug("update (%f, %f, %f)" % (min_int, better_lca, better_lcb))
+                    logging.debug(
+                        "update (%f, %f, %f)"
+                        % (min_int, better_lca, better_lcb)
+                    )
 
         logging.debug("coarse search done")
         logging.debug("better lca = " + str(better_lca))
@@ -351,11 +405,11 @@ def opt_lc_grid(self, a_min, a_max, b_min, b_max, step):
     # ========== Optimization wrappers =============
     # ==============================================
     def opt_Iext(self):
-        self.plot_sequence_emitter.emit('Coarse')
-        logging.info('Calibrating State0 (Extinction)...')
-        logging.debug('Calibrating State0 (Extinction)...')
+        self.plot_sequence_emitter.emit("Coarse")
+        logging.info("Calibrating State0 (Extinction)...")
+        logging.debug("Calibrating State0 (Extinction)...")
 
-        set_lc_state(self.mmc, self.group, 'State0')
+        set_lc_state(self.mmc, self.group, "State0")
         time.sleep(2)
 
         # Perform exhaustive search with step 0.1 over range:
@@ -366,15 +420,17 @@ def opt_Iext(self):
         logging.debug(f"Starting first grid search, step = {step}")
         logging.debug(f"================================")
 
-        best_lca, best_lcb, i_ext_ = self.opt_lc_grid(0.01, 0.5, 0.25, 0.75, step)
+        best_lca, best_lcb, i_ext_ = self.opt_lc_grid(
+            0.01, 0.5, 0.25, 0.75, step
+        )
 
         logging.debug("grid search done")
         logging.debug("lca = " + str(best_lca))
         logging.debug("lcb = " + str(best_lcb))
         logging.debug("intensity = " + str(i_ext_))
 
-        self.set_lc(best_lca, 'LCA')
-        self.set_lc(best_lcb, 'LCB')
+        self.set_lc(best_lca, "LCA")
+        self.set_lc(best_lcb, "LCB")
 
         logging.debug(f"================================")
         logging.debug(f"Starting fine search")
@@ -383,29 +439,34 @@ def opt_Iext(self):
         # Perform brent optimization around results of 2nd grid search
         # threshold not very necessary here as intensity value will
         # vary between exposure/lamp intensities
-        self.plot_sequence_emitter.emit('Fine')
-        lca, lcb, I_ext = self.optimizer.optimize(state='ext', lca_bound=0.1, lcb_bound=0.1,
-                                                  reference=self.I_Black, thresh=1, n_iter=5)
+        self.plot_sequence_emitter.emit("Fine")
+        lca, lcb, I_ext = self.optimizer.optimize(
+            state="ext",
+            lca_bound=0.1,
+            lcb_bound=0.1,
+            reference=self.I_Black,
+            thresh=1,
+            n_iter=5,
+        )
 
         # Set the Extinction state to values output from optimization
-        self.define_lc_state('State0', lca, lcb)
+        self.define_lc_state("State0", lca, lcb)
 
         self.lca_ext = lca
         self.lcb_ext = lcb
         self.I_Ext = I_ext
 
         logging.debug("fine search done")
-        logging.info(f'LCA State0 (Extinction) = {lca:.3f}')
-        logging.debug(f'LCA State0 (Extinction) = {lca:.5f}')
-        logging.info(f'LCB State0 (Extinction) = {lcb:.3f}')
-        logging.debug(f'LCB State0 (Extinction) = {lcb:.5f}')
-        logging.info(f'Intensity (Extinction) = {I_ext:.0f}')
-        logging.debug(f'Intensity (Extinction) = {I_ext:.3f}')
+        logging.info(f"LCA State0 (Extinction) = {lca:.3f}")
+        logging.debug(f"LCA State0 (Extinction) = {lca:.5f}")
+        logging.info(f"LCB State0 (Extinction) = {lcb:.3f}")
+        logging.debug(f"LCB State0 (Extinction) = {lcb:.5f}")
+        logging.info(f"Intensity (Extinction) = {I_ext:.0f}")
+        logging.debug(f"Intensity (Extinction) = {I_ext:.3f}")
 
         logging.debug("--------done--------")
         logging.info("--------done--------")
 
-
     def opt_I0(self):
         """
         no optimization performed for this.  Simply apply swing and read intensity
@@ -414,25 +475,27 @@ def opt_I0(self):
             mean of image
         """
 
-        logging.info('Calibrating State1 (I0)...')
-        logging.debug('Calibrating State1 (I0)...')
+        logging.info("Calibrating State1 (I0)...")
+        logging.debug("Calibrating State1 (I0)...")
 
         self.lca_0 = self.lca_ext - self.swing
         self.lcb_0 = self.lcb_ext
-        self.set_lc(self.lca_0, 'LCA')
-        self.set_lc(self.lcb_0, 'LCB')
+        self.set_lc(self.lca_0, "LCA")
+        self.set_lc(self.lcb_0, "LCB")
 
-        self.define_lc_state('State1', self.lca_0, self.lcb_0)
+        self.define_lc_state("State1", self.lca_0, self.lcb_0)
         intensity = snap_and_average(self.snap_manager)
         self.I_Elliptical = intensity
-        self.swing0 = np.sqrt((self.lcb_0 - self.lcb_ext) ** 2 + (self.lca_0 - self.lca_ext) ** 2)
-
-        logging.info(f'LCA State1 (I0) = {self.lca_0:.3f}')
-        logging.debug(f'LCA State1 (I0) = {self.lca_0:.5f}')
-        logging.info(f'LCB State1 (I0) = {self.lcb_0:.3f}')
-        logging.debug(f'LCB State1 (I0) = {self.lcb_0:.5f}')
-        logging.info(f'Intensity (I0) = {intensity:.0f}')
-        logging.debug(f'Intensity (I0) = {intensity:.3f}')
+        self.swing0 = np.sqrt(
+            (self.lcb_0 - self.lcb_ext) ** 2 + (self.lca_0 - self.lca_ext) ** 2
+        )
+
+        logging.info(f"LCA State1 (I0) = {self.lca_0:.3f}")
+        logging.debug(f"LCA State1 (I0) = {self.lca_0:.5f}")
+        logging.info(f"LCB State1 (I0) = {self.lcb_0:.3f}")
+        logging.debug(f"LCB State1 (I0) = {self.lcb_0:.5f}")
+        logging.info(f"Intensity (I0) = {intensity:.0f}")
+        logging.debug(f"Intensity (I0) = {intensity:.3f}")
         logging.info("--------done--------")
         logging.debug("--------done--------")
 
@@ -449,25 +512,34 @@ def opt_I45(self, lca_bound, lcb_bound):
         intensity value at optimized state
         """
         self.inten = []
-        logging.info('Calibrating State2 (I45)...')
-        logging.debug('Calibrating State2 (I45)...')
-
-        self.set_lc(self.lca_ext, 'LCA')
-        self.set_lc(self.lcb_ext - self.swing, 'LCB')
-
-        self.lca_45, self.lcb_45, intensity = self.optimizer.optimize('45', lca_bound, lcb_bound,
-                                                                      reference=self.I_Elliptical, n_iter=5, thresh=.01)
-
-        self.define_lc_state('State2', self.lca_45, self.lcb_45)
-
-        self.swing45 = np.sqrt((self.lcb_45 - self.lcb_ext) ** 2 + (self.lca_45 - self.lca_ext) ** 2)
-
-        logging.info(f'LCA State2 (I45) = {self.lca_45:.3f}')
-        logging.debug(f'LCA State2 (I45) = {self.lca_45:.5f}')
-        logging.info(f'LCB State2 (I45) = {self.lcb_45:.3f}')
-        logging.debug(f'LCB State2 (I45) = {self.lcb_45:.5f}')
-        logging.info(f'Intensity (I45) = {intensity:.0f}')
-        logging.debug(f'Intensity (I45) = {intensity:.3f}')
+        logging.info("Calibrating State2 (I45)...")
+        logging.debug("Calibrating State2 (I45)...")
+
+        self.set_lc(self.lca_ext, "LCA")
+        self.set_lc(self.lcb_ext - self.swing, "LCB")
+
+        self.lca_45, self.lcb_45, intensity = self.optimizer.optimize(
+            "45",
+            lca_bound,
+            lcb_bound,
+            reference=self.I_Elliptical,
+            n_iter=5,
+            thresh=0.01,
+        )
+
+        self.define_lc_state("State2", self.lca_45, self.lcb_45)
+
+        self.swing45 = np.sqrt(
+            (self.lcb_45 - self.lcb_ext) ** 2
+            + (self.lca_45 - self.lca_ext) ** 2
+        )
+
+        logging.info(f"LCA State2 (I45) = {self.lca_45:.3f}")
+        logging.debug(f"LCA State2 (I45) = {self.lca_45:.5f}")
+        logging.info(f"LCB State2 (I45) = {self.lcb_45:.3f}")
+        logging.debug(f"LCB State2 (I45) = {self.lcb_45:.5f}")
+        logging.info(f"Intensity (I45) = {intensity:.0f}")
+        logging.debug(f"Intensity (I45) = {intensity:.3f}")
         logging.info("--------done--------")
         logging.debug("--------done--------")
 
@@ -485,40 +557,54 @@ def opt_I60(self, lca_bound, lcb_bound):
         """
         self.inten = []
 
-        logging.info('Calibrating State2 (I60)...')
-        logging.debug('Calibrating State2 (I60)...')
+        logging.info("Calibrating State2 (I60)...")
+        logging.debug("Calibrating State2 (I60)...")
 
         # Calculate Initial Swing for initial guess to optimize around
         # Based on ratio calculated from ellpiticity/orientation of LC simulation
-        swing_ell = np.sqrt((self.lca_ext - self.lca_0) ** 2 + (self.lcb_ext - self.lcb_0) ** 2)
-        lca_swing = np.sqrt(swing_ell ** 2 / (1 + self.ratio ** 2))
+        swing_ell = np.sqrt(
+            (self.lca_ext - self.lca_0) ** 2 + (self.lcb_ext - self.lcb_0) ** 2
+        )
+        lca_swing = np.sqrt(swing_ell**2 / (1 + self.ratio**2))
         lcb_swing = self.ratio * lca_swing
 
         # Optimization
-        self.set_lc(self.lca_ext + lca_swing, 'LCA')
-        self.set_lc(self.lcb_ext + lcb_swing, 'LCB')
+        self.set_lc(self.lca_ext + lca_swing, "LCA")
+        self.set_lc(self.lcb_ext + lcb_swing, "LCB")
 
-        self.lca_60, self.lcb_60, intensity = self.optimizer.optimize('60', lca_bound, lcb_bound,
-                                                                      reference=self.I_Elliptical,
-                                                                      n_iter=5, thresh=.01)
+        self.lca_60, self.lcb_60, intensity = self.optimizer.optimize(
+            "60",
+            lca_bound,
+            lcb_bound,
+            reference=self.I_Elliptical,
+            n_iter=5,
+            thresh=0.01,
+        )
 
-        self.define_lc_state('State2', self.lca_60, self.lcb_60)
+        self.define_lc_state("State2", self.lca_60, self.lcb_60)
 
-        self.swing60 = np.sqrt((self.lcb_60 - self.lcb_ext) ** 2 + (self.lca_60 - self.lca_ext) ** 2)
+        self.swing60 = np.sqrt(
+            (self.lcb_60 - self.lcb_ext) ** 2
+            + (self.lca_60 - self.lca_ext) ** 2
+        )
 
         # Print comparison of target swing, target ratio
         # Ratio determines the orientation of the elliptical state
         # should be close to target.  Swing will vary to optimize ellipticity
-        logging.debug(f'ratio: swing_LCB / swing_LCA = {(self.lcb_ext - self.lcb_60) / (self.lca_ext - self.lca_60):.4f} \
-              | target ratio: {-self.ratio}')
-        logging.debug(f'total swing = {self.swing60:.4f} | target = {swing_ell}')
+        logging.debug(
+            f"ratio: swing_LCB / swing_LCA = {(self.lcb_ext - self.lcb_60) / (self.lca_ext - self.lca_60):.4f} \
+              | target ratio: {-self.ratio}"
+        )
+        logging.debug(
+            f"total swing = {self.swing60:.4f} | target = {swing_ell}"
+        )
 
         logging.info(f"LCA State2 (I60) = {self.lca_60:.3f}")
         logging.debug(f"LCA State2 (I60) = {self.lca_60:.5f}")
         logging.info(f"LCB State2 (I60) = {self.lcb_60:.3f}")
         logging.debug(f"LCB State2 (I60) = {self.lcb_60:.5f}")
-        logging.info(f'Intensity (I60) = {intensity:.0f}')
-        logging.debug(f'Intensity (I60) = {intensity:.3f}')
+        logging.info(f"Intensity (I60) = {intensity:.0f}")
+        logging.debug(f"Intensity (I60) = {intensity:.3f}")
         logging.info("--------done--------")
         logging.debug("--------done--------")
 
@@ -534,28 +620,36 @@ def opt_I90(self, lca_bound, lcb_bound):
         lca, lcb value at optimized state
         intensity value at optimized state
         """
-        logging.info('Calibrating State3 (I90)...')
-        logging.debug('Calibrating State3 (I90)...')
+        logging.info("Calibrating State3 (I90)...")
+        logging.debug("Calibrating State3 (I90)...")
 
         self.inten = []
 
-        self.set_lc(self.lca_ext + self.swing, 'LCA')
-        self.set_lc(self.lcb_ext, 'LCB')
-
-        self.lca_90, self.lcb_90, intensity = self.optimizer.optimize('90', lca_bound, lcb_bound,
-                                                                      reference=self.I_Elliptical,
-                                                                      n_iter=5, thresh=.01)
-
-        self.define_lc_state('State3', self.lca_90, self.lcb_90)
-
-        self.swing90 = np.sqrt((self.lcb_90 - self.lcb_ext) ** 2 + (self.lca_90 - self.lca_ext) ** 2)
-
-        logging.info(f'LCA State3 (I90) = {self.lca_90:.3f}')
-        logging.debug(f'LCA State3 (I90) = {self.lca_90:.5f}')
-        logging.info(f'LCB State3 (I90) = {self.lcb_90:.3f}')
-        logging.debug(f'LCB State3 (I90) = {self.lcb_90:.5f}')
-        logging.info(f'Intensity (I90) = {intensity:.0f}')
-        logging.debug(f'Intensity (I90) = {intensity:.3f}')
+        self.set_lc(self.lca_ext + self.swing, "LCA")
+        self.set_lc(self.lcb_ext, "LCB")
+
+        self.lca_90, self.lcb_90, intensity = self.optimizer.optimize(
+            "90",
+            lca_bound,
+            lcb_bound,
+            reference=self.I_Elliptical,
+            n_iter=5,
+            thresh=0.01,
+        )
+
+        self.define_lc_state("State3", self.lca_90, self.lcb_90)
+
+        self.swing90 = np.sqrt(
+            (self.lcb_90 - self.lcb_ext) ** 2
+            + (self.lca_90 - self.lca_ext) ** 2
+        )
+
+        logging.info(f"LCA State3 (I90) = {self.lca_90:.3f}")
+        logging.debug(f"LCA State3 (I90) = {self.lca_90:.5f}")
+        logging.info(f"LCB State3 (I90) = {self.lcb_90:.3f}")
+        logging.debug(f"LCB State3 (I90) = {self.lcb_90:.5f}")
+        logging.info(f"Intensity (I90) = {intensity:.0f}")
+        logging.debug(f"Intensity (I90) = {intensity:.3f}")
         logging.info("--------done--------")
         logging.debug("--------done--------")
 
@@ -571,39 +665,53 @@ def opt_I120(self, lca_bound, lcb_bound):
         lca, lcb value at optimized state
         intensity value at optimized state
         """
-        logging.info('Calibrating State3 (I120)...')
-        logging.debug('Calibrating State3 (I120)...')
+        logging.info("Calibrating State3 (I120)...")
+        logging.debug("Calibrating State3 (I120)...")
 
         # Calculate Initial Swing for initial guess to optimize around
         # Based on ratio calculated from ellpiticity/orientation of LC simulation
-        swing_ell = np.sqrt((self.lca_ext - self.lca_0) ** 2 + (self.lcb_ext - self.lcb_0) ** 2)
-        lca_swing = np.sqrt(swing_ell ** 2 / (1 + self.ratio ** 2))
+        swing_ell = np.sqrt(
+            (self.lca_ext - self.lca_0) ** 2 + (self.lcb_ext - self.lcb_0) ** 2
+        )
+        lca_swing = np.sqrt(swing_ell**2 / (1 + self.ratio**2))
         lcb_swing = self.ratio * lca_swing
 
         # Brent Optimization
-        self.set_lc(self.lca_ext + lca_swing, 'LCA')
-        self.set_lc(self.lcb_ext - lcb_swing, 'LCB')
+        self.set_lc(self.lca_ext + lca_swing, "LCA")
+        self.set_lc(self.lcb_ext - lcb_swing, "LCB")
 
-        self.lca_120, self.lcb_120, intensity = self.optimizer.optimize('120', lca_bound, lcb_bound,
-                                                                      reference=self.I_Elliptical,
-                                                                      n_iter=5, thresh=.01)
+        self.lca_120, self.lcb_120, intensity = self.optimizer.optimize(
+            "120",
+            lca_bound,
+            lcb_bound,
+            reference=self.I_Elliptical,
+            n_iter=5,
+            thresh=0.01,
+        )
 
-        self.define_lc_state('State3', self.lca_120, self.lcb_120)
+        self.define_lc_state("State3", self.lca_120, self.lcb_120)
 
-        self.swing120 = np.sqrt((self.lcb_120 - self.lcb_ext) ** 2 + (self.lca_120 - self.lca_ext) ** 2)
+        self.swing120 = np.sqrt(
+            (self.lcb_120 - self.lcb_ext) ** 2
+            + (self.lca_120 - self.lca_ext) ** 2
+        )
 
         # Print comparison of target swing, target ratio
         # Ratio determines the orientation of the elliptical state
         # should be close to target.  Swing will vary to optimize ellipticity
-        logging.debug(f'ratio: swing_LCB / swing_LCA = {(self.lcb_ext - self.lcb_120) / (self.lca_ext - self.lca_120):.4f}\
-             | target ratio: {self.ratio}')
-        logging.debug(f'total swing = {self.swing120:.4f} | target = {swing_ell}')
+        logging.debug(
+            f"ratio: swing_LCB / swing_LCA = {(self.lcb_ext - self.lcb_120) / (self.lca_ext - self.lca_120):.4f}\
+             | target ratio: {self.ratio}"
+        )
+        logging.debug(
+            f"total swing = {self.swing120:.4f} | target = {swing_ell}"
+        )
         logging.info(f"LCA State3 (I120) = {self.lca_120:.3f}")
         logging.debug(f"LCA State3 (I120) = {self.lca_120:.5f}")
         logging.info(f"LCB State3 (I120) = {self.lcb_120:.3f}")
         logging.debug(f"LCB State3 (I120) = {self.lcb_120:.5f}")
-        logging.info(f'Intensity (I120) = {intensity:.0f}')
-        logging.debug(f'Intensity (I120) = {intensity:.3f}')
+        logging.info(f"Intensity (I120) = {intensity:.0f}")
+        logging.debug(f"Intensity (I120) = {intensity:.3f}")
         logging.info("--------done--------")
         logging.debug("--------done--------")
 
@@ -620,33 +728,41 @@ def opt_I135(self, lca_bound, lcb_bound):
         intensity value at optimized state
         """
 
-        logging.info('Calibrating State4 (I135)...')
-        logging.debug('Calibrating State4 (I135)...')
+        logging.info("Calibrating State4 (I135)...")
+        logging.debug("Calibrating State4 (I135)...")
         self.inten = []
 
-        self.set_lc(self.lca_ext, 'LCA')
-        self.set_lc(self.lcb_ext + self.swing, 'LCB')
-
-        self.lca_135, self.lcb_135, intensity = self.optimizer.optimize('135', lca_bound, lcb_bound,
-                                                                      reference=self.I_Elliptical,
-                                                                      n_iter=5, thresh=.01)
-
-        self.define_lc_state('State4', self.lca_135, self.lcb_135)
-
-        self.swing135 = np.sqrt((self.lcb_135 - self.lcb_ext) ** 2 + (self.lca_135 - self.lca_ext) ** 2)
-
-        logging.info(f'LCA State4 (I135) = {self.lca_135:.3f}')
-        logging.debug(f'LCA State4 (I135) = {self.lca_135:.5f}')
-        logging.info(f'LCB State4 (I135) = {self.lcb_135:.3f}')
-        logging.debug(f'LCB State4 (I135) = {self.lcb_135:.5f}')
-        logging.info(f'Intensity (I135) = {intensity:.0f}')
-        logging.debug(f'Intensity (I135) = {intensity:.3f}')
+        self.set_lc(self.lca_ext, "LCA")
+        self.set_lc(self.lcb_ext + self.swing, "LCB")
+
+        self.lca_135, self.lcb_135, intensity = self.optimizer.optimize(
+            "135",
+            lca_bound,
+            lcb_bound,
+            reference=self.I_Elliptical,
+            n_iter=5,
+            thresh=0.01,
+        )
+
+        self.define_lc_state("State4", self.lca_135, self.lcb_135)
+
+        self.swing135 = np.sqrt(
+            (self.lcb_135 - self.lcb_ext) ** 2
+            + (self.lca_135 - self.lca_ext) ** 2
+        )
+
+        logging.info(f"LCA State4 (I135) = {self.lca_135:.3f}")
+        logging.debug(f"LCA State4 (I135) = {self.lca_135:.5f}")
+        logging.info(f"LCB State4 (I135) = {self.lcb_135:.3f}")
+        logging.debug(f"LCB State4 (I135) = {self.lcb_135:.5f}")
+        logging.info(f"Intensity (I135) = {intensity:.0f}")
+        logging.debug(f"Intensity (I135) = {intensity:.3f}")
         logging.info("--------done--------")
         logging.debug("--------done--------")
 
     def open_shutter(self):
-        if self.shutter_device == '': # no shutter
-            input('Please manually open the shutter and press <Enter>')
+        if self.shutter_device == "":  # no shutter
+            input("Please manually open the shutter and press <Enter>")
         else:
             self.mmc.setShutterOpen(True)
 
@@ -658,9 +774,13 @@ def reset_shutter(self):
         -------
 
         """
-        if self.shutter_device == '': # no shutter
-            input('Please reset the shutter to its original state and press <Enter>')
-            logging.info("This is the end of the command-line instructions. You can return to the napari window.")
+        if self.shutter_device == "":  # no shutter
+            input(
+                "Please reset the shutter to its original state and press <Enter>"
+            )
+            logging.info(
+                "This is the end of the command-line instructions. You can return to the napari window."
+            )
         else:
             self.mmc.setAutoShutter(self._auto_shutter_state)
             self.mmc.setShutterOpen(self._shutter_state)
@@ -669,8 +789,10 @@ def close_shutter_and_calc_blacklevel(self):
         self._auto_shutter_state = self.mmc.getAutoShutter()
         self._shutter_state = self.mmc.getShutterOpen()
 
-        if self.shutter_device == '':  # no shutter
-            show_warning('No shutter found. Please follow the command-line instructions...')
+        if self.shutter_device == "":  # no shutter
+            show_warning(
+                "No shutter found. Please follow the command-line instructions..."
+            )
             shutter_warning_msg = """
             recOrder could not find an automatic shutter configured through Micro-Manager.
             >>> If you would like manually enter the black level, enter an integer or float and press <Enter>
@@ -678,7 +800,7 @@ def close_shutter_and_calc_blacklevel(self):
             """
 
             in_string = input(shutter_warning_msg)
-            if in_string.isdigit(): # True if positive integer
+            if in_string.isdigit():  # True if positive integer
                 self.I_Black = float(in_string)
                 return
         else:
@@ -699,7 +821,10 @@ def get_full_roi(self):
         # Get Image Parameters
         self.mmc.snapImage()
         self.mmc.getImage()
-        self.height, self.width = self.mmc.getImageHeight(), self.mmc.getImageWidth()
+        self.height, self.width = (
+            self.mmc.getImageHeight(),
+            self.mmc.getImageWidth(),
+        )
         self.ROI = (0, 0, self.width, self.height)
 
     def check_and_get_roi(self):
@@ -711,15 +836,24 @@ def check_and_get_roi(self):
         for i in range(size):
             win = windows.get(i).toFront()
             time.sleep(0.05)
-            roi = self.mm.displays().getActiveDataViewer().getImagePlus().getRoi()
+            roi = (
+                self.mm.displays()
+                .getActiveDataViewer()
+                .getImagePlus()
+                .getRoi()
+            )
             if roi != None:
                 boxes.append(roi)
 
         if len(boxes) == 0:
-            raise ValueError('No ROI Bounding Box Found, Please Draw Bounding Box on the Preview (live) Window')
+            raise ValueError(
+                "No ROI Bounding Box Found, Please Draw Bounding Box on the Preview (live) Window"
+            )
 
         if len(boxes) > 1:
-            raise ValueError('More than one Bounding Box Found, Please Remove any box not on the preview (live) window')
+            raise ValueError(
+                "More than one Bounding Box Found, Please Remove any box not on the preview (live) window"
+            )
 
         if len(boxes) == 1:
             rect = boxes[0].getBounds()
@@ -729,50 +863,83 @@ def display_and_check_ROI(self, rect):
 
         img = snap_image(self.mmc)
 
-        print('Will Calibrate Using this ROI:')
+        print("Will Calibrate Using this ROI:")
         fig, ax = plt.subplots()
 
-        ax.imshow(np.reshape(img, (self.height, self.width)), 'gray')
-        box = patches.Rectangle((rect.x, rect.y), rect.width, rect.height, linewidth=2, edgecolor='r', facecolor='none')
+        ax.imshow(np.reshape(img, (self.height, self.width)), "gray")
+        box = patches.Rectangle(
+            (rect.x, rect.y),
+            rect.width,
+            rect.height,
+            linewidth=2,
+            edgecolor="r",
+            facecolor="none",
+        )
         ax.add_patch(box)
         plt.show()
 
-        cont = input('Would You Like to Calibrate Using this ROI? (Yes/No): \t')
+        cont = input(
+            "Would You Like to Calibrate Using this ROI? (Yes/No): \t"
+        )
 
-        if cont in ['Yes', 'Y', 'yes', 'ye', 'y', '']:
+        if cont in ["Yes", "Y", "yes", "ye", "y", ""]:
             return True
 
-        if cont in ['No', 'N', 'no', 'n']:
+        if cont in ["No", "N", "no", "n"]:
             return False
 
         else:
-            raise ValueError('Did not understand your answer, please check spelling')
-
-    def calculate_extinction(self, swing, black_level, intensity_extinction, intensity_elliptical):
-        return np.round((1 / np.sin(np.pi * swing) ** 2) * \
-               (intensity_elliptical - black_level) / (intensity_extinction - black_level), 2)
+            raise ValueError(
+                "Did not understand your answer, please check spelling"
+            )
+
+    def calculate_extinction(
+        self, swing, black_level, intensity_extinction, intensity_elliptical
+    ):
+        return np.round(
+            (1 / np.sin(np.pi * swing) ** 2)
+            * (intensity_elliptical - black_level)
+            / (intensity_extinction - black_level),
+            2,
+        )
 
     def calc_inst_matrix(self):
 
-        if self.calib_scheme == '4-State':
+        if self.calib_scheme == "4-State":
             chi = self.swing
-            inst_mat = np.array([[1, 0, 0, -1],
-                                 [1, np.sin(2 * np.pi * chi), 0, -np.cos(2 * np.pi * chi)],
-                                 [1, -0.5 * np.sin(2 * np.pi * chi),
-                                  np.sqrt(3) * np.cos(np.pi * chi) * np.sin(np.pi * chi), -np.cos(2 * np.pi * chi)],
-                                 [1, -0.5 * np.sin(2 * np.pi * chi), -np.sqrt(3) / 2 * np.sin(2 * np.pi * chi),
-                                  -np.cos(2 * np.pi * chi)]])
+            inst_mat = np.array(
+                [
+                    [1, 0, 0, -1],
+                    [1, np.sin(2 * np.pi * chi), 0, -np.cos(2 * np.pi * chi)],
+                    [
+                        1,
+                        -0.5 * np.sin(2 * np.pi * chi),
+                        np.sqrt(3) * np.cos(np.pi * chi) * np.sin(np.pi * chi),
+                        -np.cos(2 * np.pi * chi),
+                    ],
+                    [
+                        1,
+                        -0.5 * np.sin(2 * np.pi * chi),
+                        -np.sqrt(3) / 2 * np.sin(2 * np.pi * chi),
+                        -np.cos(2 * np.pi * chi),
+                    ],
+                ]
+            )
 
             return inst_mat
 
-        if self.calib_scheme == '5-State':
+        if self.calib_scheme == "5-State":
             chi = self.swing * 2 * np.pi
 
-            inst_mat = np.array([[1, 0, 0, -1],
-                                 [1, np.sin(chi), 0, -np.cos(chi)],
-                                 [1, 0, np.sin(chi), -np.cos(chi)],
-                                 [1, -np.sin(chi), 0, -np.cos(chi)],
-                                 [1, 0, -np.sin(chi), -np.cos(chi)]])
+            inst_mat = np.array(
+                [
+                    [1, 0, 0, -1],
+                    [1, np.sin(chi), 0, -np.cos(chi)],
+                    [1, 0, np.sin(chi), -np.cos(chi)],
+                    [1, -np.sin(chi), 0, -np.cos(chi)],
+                    [1, 0, -np.sin(chi), -np.cos(chi)],
+                ]
+            )
 
             return inst_mat
 
@@ -781,57 +948,86 @@ def write_metadata(self, notes=None):
         inst_mat = self.calc_inst_matrix()
         inst_mat = np.around(inst_mat, decimals=5).tolist()
 
-        metadata = {'Summary': {
-                        'Timestamp': str(datetime.now()),
-                        'recOrder-napari version': version('recOrder-napari'),
-                        'waveorder version': version('waveorder')},
-                    'Calibration': {
-                        'Calibration scheme': self.calib_scheme,
-                        'Swing (waves)': self.swing,
-                        'Wavelength (nm)': self.wavelength,
-                        'Retardance to voltage interpolation method': self.calib.interp_method,
-                        'LC control mode': self.mode,
-                        'Black level': np.round(self.I_Black, 2),
-                        'Extinction ratio': self.extinction_ratio,
-                        'ROI (x, y, width, height)': self.ROI},
-                    'Notes': notes
-                    }
-
-        if self.calib_scheme == '4-State':
-            metadata['Calibration'].update({
-                'Channel names': [f"State{i}" for i in range(4)],
-                'LC retardance': {f'LC{i}_{j}': np.around(getattr(self, f'lc{i.lower()}_{j}'), decimals=6)
-                                  for j in ['ext', '0', '60', '120']
-                                  for i in ['A', 'B']},
-                'LC voltage': {f'LC{i}_{j}': np.around(self.calib.get_voltage(getattr(self, f'lc{i.lower()}_{j}')), decimals=4)
-                               for j in ['ext', '0', '60', '120']
-                               for i in ['A', 'B']},
-                'Swing_0': np.around(self.swing0, decimals=3),
-                'Swing_60': np.around(self.swing60, decimals=3),
-                'Swing_120': np.around(self.swing120, decimals=3),
-                'Instrument matrix': inst_mat
-            })
-
-        elif self.calib_scheme == '5-State':
-            metadata['Calibration'].update({
-                'Channel names': [f"State{i}" for i in range(5)],
-                'LC retardance': {f'LC{i}_{j}': np.around(getattr(self, f'lc{i.lower()}_{j}'), decimals=6)
-                                  for j in ['ext', '0', '45', '90', '135']
-                                  for i in ['A', 'B']},
-                'LC voltage': {f'LC{i}_{j}': np.around(self.calib.get_voltage(getattr(self, f'lc{i.lower()}_{j}')), decimals=4)
-                               for j in ['ext', '0', '45', '90', '135']
-                               for i in ['A', 'B']},
-                'Swing_0': np.around(self.swing0, decimals=3),
-                'Swing_45': np.around(self.swing45, decimals=3),
-                'Swing_90': np.around(self.swing90, decimals=3),
-                'Swing_135': np.around(self.swing135, decimals=3),
-                'Instrument matrix': inst_mat
-            })
-
-        if not self.meta_file.endswith('.txt'):
-            self.meta_file += '.txt'
-
-        with open(self.meta_file, 'w') as metafile:
+        metadata = {
+            "Summary": {
+                "Timestamp": str(datetime.now()),
+                "recOrder-napari version": version("recOrder-napari"),
+                "waveorder version": version("waveorder"),
+            },
+            "Calibration": {
+                "Calibration scheme": self.calib_scheme,
+                "Swing (waves)": self.swing,
+                "Wavelength (nm)": self.wavelength,
+                "Retardance to voltage interpolation method": self.calib.interp_method,
+                "LC control mode": self.mode,
+                "Black level": np.round(self.I_Black, 2),
+                "Extinction ratio": self.extinction_ratio,
+                "ROI (x, y, width, height)": self.ROI,
+            },
+            "Notes": notes,
+        }
+
+        if self.calib_scheme == "4-State":
+            metadata["Calibration"].update(
+                {
+                    "Channel names": [f"State{i}" for i in range(4)],
+                    "LC retardance": {
+                        f"LC{i}_{j}": np.around(
+                            getattr(self, f"lc{i.lower()}_{j}"), decimals=6
+                        )
+                        for j in ["ext", "0", "60", "120"]
+                        for i in ["A", "B"]
+                    },
+                    "LC voltage": {
+                        f"LC{i}_{j}": np.around(
+                            self.calib.get_voltage(
+                                getattr(self, f"lc{i.lower()}_{j}")
+                            ),
+                            decimals=4,
+                        )
+                        for j in ["ext", "0", "60", "120"]
+                        for i in ["A", "B"]
+                    },
+                    "Swing_0": np.around(self.swing0, decimals=3),
+                    "Swing_60": np.around(self.swing60, decimals=3),
+                    "Swing_120": np.around(self.swing120, decimals=3),
+                    "Instrument matrix": inst_mat,
+                }
+            )
+
+        elif self.calib_scheme == "5-State":
+            metadata["Calibration"].update(
+                {
+                    "Channel names": [f"State{i}" for i in range(5)],
+                    "LC retardance": {
+                        f"LC{i}_{j}": np.around(
+                            getattr(self, f"lc{i.lower()}_{j}"), decimals=6
+                        )
+                        for j in ["ext", "0", "45", "90", "135"]
+                        for i in ["A", "B"]
+                    },
+                    "LC voltage": {
+                        f"LC{i}_{j}": np.around(
+                            self.calib.get_voltage(
+                                getattr(self, f"lc{i.lower()}_{j}")
+                            ),
+                            decimals=4,
+                        )
+                        for j in ["ext", "0", "45", "90", "135"]
+                        for i in ["A", "B"]
+                    },
+                    "Swing_0": np.around(self.swing0, decimals=3),
+                    "Swing_45": np.around(self.swing45, decimals=3),
+                    "Swing_90": np.around(self.swing90, decimals=3),
+                    "Swing_135": np.around(self.swing135, decimals=3),
+                    "Instrument matrix": inst_mat,
+                }
+            )
+
+        if not self.meta_file.endswith(".txt"):
+            self.meta_file += ".txt"
+
+        with open(self.meta_file, "w") as metafile:
             json.dump(metadata, metafile, indent=1)
 
     def _add_colorbar(self, mappable):
@@ -868,14 +1064,22 @@ def _capture_state(self, state: str, n_avg: int):
 
     def _plot_bg_images(self, imgs):
 
-        img_names = ['Extinction', '0', '60', '120'] if len(imgs) == 4 else ['Extinction', '0', '45', '90', 135]
-        fig, ax = plt.subplots(2, 2, figsize=(20, 20)) if len(imgs) == 4 else plt.subplots(3, 2, figsize=(20, 20))
+        img_names = (
+            ["Extinction", "0", "60", "120"]
+            if len(imgs) == 4
+            else ["Extinction", "0", "45", "90", 135]
+        )
+        fig, ax = (
+            plt.subplots(2, 2, figsize=(20, 20))
+            if len(imgs) == 4
+            else plt.subplots(3, 2, figsize=(20, 20))
+        )
 
         img_idx = 0
         for ax1 in range(len(ax[:, 0])):
             for ax2 in range(len(ax[0, :])):
                 if img_idx < len(imgs):
-                    im = ax[ax1, ax2].imshow(imgs[img_idx], 'gray')
+                    im = ax[ax1, ax2].imshow(imgs[img_idx], "gray")
                     ax[ax1, ax2].set_title(img_names[img_idx])
                     self._add_colorbar(im)
                 else:
@@ -904,7 +1108,9 @@ def pol_states(self):
         elif self.calib_scheme == "5-State":
             pols = ("ext", "0", "45", "90", "135")
         else:
-            raise ValueError(f"Invalid calibration state: {self.calib_scheme}.")
+            raise ValueError(
+                f"Invalid calibration state: {self.calib_scheme}."
+            )
         return pols
 
     @property
@@ -919,14 +1125,14 @@ def lc_states(self):
         lc_sides = ["A", "B"]
         return {
             f"LC{lc_side}": [
-                self.__getattribute__("lc" + lc_side.lower() + "_" + pol) 
+                self.__getattribute__("lc" + lc_side.lower() + "_" + pol)
                 for pol in self.pol_states
             ]
             for lc_side in lc_sides
         }
 
     def capture_bg(self, n_avg, directory):
-        """"
+        """ "
         This function will capture an image at every state
         and save to specified directory
         This may throw errors depending on the micromanager config file--
@@ -940,38 +1146,38 @@ def capture_bg(self, n_avg, directory):
         if not os.path.exists(directory):
             os.makedirs(directory)
 
-        logging.info('Capturing Background')
+        logging.info("Capturing Background")
         self._auto_shutter_state = self.mmc.getAutoShutter()
         self._shutter_state = self.mmc.getShutterOpen()
         self.open_shutter()
-        logging.debug('Capturing Background State0')
+        logging.debug("Capturing Background State0")
 
-        state0 = self._capture_state('State0', n_avg)
-        logging.debug('Saving Background State0')
-        tiff.imsave(os.path.join(directory, 'State0.tif'), state0)
+        state0 = self._capture_state("State0", n_avg)
+        logging.debug("Saving Background State0")
+        tiff.imsave(os.path.join(directory, "State0.tif"), state0)
 
-        logging.debug('Capturing Background State1')
-        state1 = self._capture_state('State1', n_avg)
-        logging.debug('Saving Background State1')
-        tiff.imsave(os.path.join(directory, 'State1.tif'), state1)
+        logging.debug("Capturing Background State1")
+        state1 = self._capture_state("State1", n_avg)
+        logging.debug("Saving Background State1")
+        tiff.imsave(os.path.join(directory, "State1.tif"), state1)
 
-        logging.debug('Capturing Background State2')
-        state2 = self._capture_state('State2', n_avg)
-        logging.debug('Saving Background State2')
-        tiff.imsave(os.path.join(directory, 'State2.tif'), state2)
+        logging.debug("Capturing Background State2")
+        state2 = self._capture_state("State2", n_avg)
+        logging.debug("Saving Background State2")
+        tiff.imsave(os.path.join(directory, "State2.tif"), state2)
 
-        logging.debug('Capturing Background State3')
-        state3 = self._capture_state('State3', n_avg)
-        logging.debug('Saving Background State3')
-        tiff.imsave(os.path.join(directory, 'State3.tif'), state3)
+        logging.debug("Capturing Background State3")
+        state3 = self._capture_state("State3", n_avg)
+        logging.debug("Saving Background State3")
+        tiff.imsave(os.path.join(directory, "State3.tif"), state3)
 
         imgs = [state0, state1, state2, state3]
 
-        if self.calib_scheme == '5-State':
-            logging.debug('Capturing Background State4')
-            state4 = self._capture_state('State4', n_avg)
-            logging.debug('Saving Background State4')
-            tiff.imsave(os.path.join(directory, 'State4.tif'), state4)
+        if self.calib_scheme == "5-State":
+            logging.debug("Capturing Background State4")
+            state4 = self._capture_state("State4", n_avg)
+            logging.debug("Saving Background State4")
+            tiff.imsave(os.path.join(directory, "State4.tif"), state4)
             imgs.append(state4)
 
         # self._plot_bg_images(np.asarray(imgs))
@@ -985,7 +1191,7 @@ class CalibrationData:
     Interpolates LC calibration data between retardance (in waves), voltage (in mV), and wavelength (in nm)
     """
 
-    def __init__(self, path, wavelength=532, interp_method='linear'):
+    def __init__(self, path, wavelength=532, interp_method="linear"):
         """
 
         Parameters
@@ -999,21 +1205,25 @@ def __init__(self, path, wavelength=532, interp_method='linear'):
         """
 
         header, raw_data = self.read_data(path)
-        self.calib_wavelengths = np.array([i[:3] for i in header[1::3]]).astype('double')
+        self.calib_wavelengths = np.array(
+            [i[:3] for i in header[1::3]]
+        ).astype("double")
 
         self.wavelength = None
         self.V_min = 0.0
         self.V_max = 20.0
 
-        if interp_method in ['linear', 'schnoor_fit']:
+        if interp_method in ["linear", "schnoor_fit"]:
             self.interp_method = interp_method
         else:
-            raise ValueError('Unknown interpolation method.')
+            raise ValueError("Unknown interpolation method.")
 
         self.set_wavelength(wavelength)
-        if interp_method == 'linear':
-            self.interpolate_data(raw_data, self.calib_wavelengths)  # calib_wavelengths is not used, values hardcoded
-        elif interp_method == 'schnoor_fit':
+        if interp_method == "linear":
+            self.interpolate_data(
+                raw_data, self.calib_wavelengths
+            )  # calib_wavelengths is not used, values hardcoded
+        elif interp_method == "schnoor_fit":
             self.fit_params = self.fit_data(raw_data, self.calib_wavelengths)
 
         self.ret_min = self.get_retardance(self.V_max)
@@ -1055,10 +1265,10 @@ def read_data(path):
             Calibration data. Voltage is in millivolts and retardance is in nanometers
 
         """
-        with open(path, 'r') as f:
-            header = f.readline().strip().split(',')
+        with open(path, "r") as f:
+            header = f.readline().strip().split(",")
 
-        raw_data = np.loadtxt(path, delimiter=',', comments='-', skiprows=3)
+        raw_data = np.loadtxt(path, delimiter=",", comments="-", skiprows=3)
         return header, raw_data
 
     @staticmethod
@@ -1080,7 +1290,7 @@ def schnoor_fit(V, a, b1, b2, c, d, e, wavelength):
             Retardance in nanometers
 
         """
-        retardance = a + (b1 + b2 / wavelength ** 2) / (1 + (V / c) ** d) ** e
+        retardance = a + (b1 + b2 / wavelength**2) / (1 + (V / c) ** d) ** e
 
         return retardance
 
@@ -1104,7 +1314,9 @@ def schnoor_fit_inv(retardance, a, b1, b2, c, d, e, wavelength):
 
         """
 
-        voltage = c * (((b1 + b2 / wavelength ** 2) / (retardance - a)) ** (1 / e) - 1) ** (1 / d)
+        voltage = c * (
+            ((b1 + b2 / wavelength**2) / (retardance - a)) ** (1 / e) - 1
+        ) ** (1 / d)
 
         return voltage
 
@@ -1115,24 +1327,37 @@ def _fun(x, wavelengths, xdata, ydata):
         return res.flatten()
 
     def set_wavelength(self, wavelength):
-        if len(self.calib_wavelengths) == 1 and wavelength != self.calib_wavelengths:
-            raise ValueError("Calibration is not provided at this wavelength. "
-                             "Wavelength dependence of LC retardance vs voltage cannot be extrapolated.")
-
-        if wavelength < self.calib_wavelengths.min() or \
-                wavelength > self.calib_wavelengths.max():
-            warnings.warn("Specified wavelength is outside of the calibration range. "
-                          "LC retardance vs voltage data will be extrapolated at this wavelength.")
+        if (
+            len(self.calib_wavelengths) == 1
+            and wavelength != self.calib_wavelengths
+        ):
+            raise ValueError(
+                "Calibration is not provided at this wavelength. "
+                "Wavelength dependence of LC retardance vs voltage cannot be extrapolated."
+            )
+
+        if (
+            wavelength < self.calib_wavelengths.min()
+            or wavelength > self.calib_wavelengths.max()
+        ):
+            warnings.warn(
+                "Specified wavelength is outside of the calibration range. "
+                "LC retardance vs voltage data will be extrapolated at this wavelength."
+            )
 
         self.wavelength = wavelength
-        if self.interp_method == 'linear':
+        if self.interp_method == "linear":
             # Interpolation of calib beyond this range produce strange results.
             if self.wavelength < 450:
                 self.wavelength = 450
-                warnings.warn("Wavelength is limited to 450-720 nm for this interpolation method.")
+                warnings.warn(
+                    "Wavelength is limited to 450-720 nm for this interpolation method."
+                )
             if self.wavelength > 720:
                 self.wavelength = 720
-                warnings.warn("Wavelength is limited to 450-720 nm for this interpolation method.")
+                warnings.warn(
+                    "Wavelength is limited to 450-720 nm for this interpolation method."
+                )
 
     def fit_data(self, raw_data, calib_wavelengths):
         """
@@ -1150,13 +1375,18 @@ def fit_data(self, raw_data, calib_wavelengths):
         -------
 
         """
-        xdata = raw_data[:, 0::3] / 1000    # convert to volts
-        ydata = raw_data[:, 1::3]           # in nanometers
+        xdata = raw_data[:, 0::3] / 1000  # convert to volts
+        ydata = raw_data[:, 1::3]  # in nanometers
 
         x0 = [10, 1000, 1e7, 1, 10, 0.1]
-        p = least_squares(self._fun, x0, method='trf', args=(calib_wavelengths, xdata, ydata),
-                          bounds=((-np.inf, 0, 0, 0, 0, 0), (np.inf,)*6),
-                          x_scale=[10, 1000, 1e7, 1, 10, 0.1])
+        p = least_squares(
+            self._fun,
+            x0,
+            method="trf",
+            args=(calib_wavelengths, xdata, ydata),
+            bounds=((-np.inf, 0, 0, 0, 0, 0), (np.inf,) * 6),
+            x_scale=[10, 1000, 1e7, 1, 10, 0.1],
+        )
 
         if not p.success:
             raise RuntimeError("Schnoor fit to calibration data did not work.")
@@ -1166,7 +1396,9 @@ def fit_data(self, raw_data, calib_wavelengths):
         slope, intercept, r_value, *_ = linregress(y, y_hat)
         r_squared = r_value**2
         if r_squared < 0.999:
-            warnings.warn(f'Schnoor fit has R2 value of {r_squared:.5f}, fit may not have worked well.')
+            warnings.warn(
+                f"Schnoor fit has R2 value of {r_squared:.5f}, fit may not have worked well."
+            )
 
         return p.x
 
@@ -1203,8 +1435,16 @@ def interpolate_data(self, raw_data, calib_wavelengths):
             fact1 = np.abs(490 - wavelength_new) / (546 - 490)
             fact2 = np.abs(546 - wavelength_new) / (546 - 490)
 
-            temp_curve = np.asarray([[i, 2 * new_a1_y[i] - (fact1 * new_a1_y[i] + fact2 * new_a2_y[i])]
-                          for i in range(len(new_a1_y))])
+            temp_curve = np.asarray(
+                [
+                    [
+                        i,
+                        2 * new_a1_y[i]
+                        - (fact1 * new_a1_y[i] + fact2 * new_a2_y[i]),
+                    ]
+                    for i in range(len(new_a1_y))
+                ]
+            )
             self.spline = interp1d(temp_curve[:, 0], temp_curve[:, 1])
             self.curve = self.spline(x_range)
 
@@ -1217,12 +1457,19 @@ def interpolate_data(self, raw_data, calib_wavelengths):
             fact1 = np.abs(630 - wavelength_new) / (630 - 546)
             fact2 = np.abs(546 - wavelength_new) / (630 - 546)
 
-            temp_curve = np.asarray([[i, 2 * new_a1_y[i] - (fact1 * new_a1_y[i] + fact2 * new_a2_y[i])]
-                                     for i in range(len(new_a1_y))])
+            temp_curve = np.asarray(
+                [
+                    [
+                        i,
+                        2 * new_a1_y[i]
+                        - (fact1 * new_a1_y[i] + fact2 * new_a2_y[i]),
+                    ]
+                    for i in range(len(new_a1_y))
+                ]
+            )
             self.spline = interp1d(temp_curve[:, 0], temp_curve[:, 1])
             self.curve = self.spline(x_range)
 
-
         elif 490 < self.wavelength < 546:
 
             new_a1_y = np.interp(x_range, x_range, spline490(x_range))
@@ -1231,7 +1478,12 @@ def interpolate_data(self, raw_data, calib_wavelengths):
             fact1 = np.abs(490 - self.wavelength) / (546 - 490)
             fact2 = np.abs(546 - self.wavelength) / (546 - 490)
 
-            temp_curve = np.asarray([[i, fact1 * new_a1_y[i] + fact2 * new_a2_y[i]] for i in range(len(new_a1_y))])
+            temp_curve = np.asarray(
+                [
+                    [i, fact1 * new_a1_y[i] + fact2 * new_a2_y[i]]
+                    for i in range(len(new_a1_y))
+                ]
+            )
             self.spline = interp1d(temp_curve[:, 0], temp_curve[:, 1])
             self.curve = self.spline(x_range)
 
@@ -1243,7 +1495,12 @@ def interpolate_data(self, raw_data, calib_wavelengths):
             fact1 = np.abs(546 - self.wavelength) / (630 - 546)
             fact2 = np.abs(630 - self.wavelength) / (630 - 546)
 
-            temp_curve = np.asarray([[i, fact1 * new_a1_y[i] + fact2 * new_a2_y[i]] for i in range(len(new_a1_y))])
+            temp_curve = np.asarray(
+                [
+                    [i, fact1 * new_a1_y[i] + fact2 * new_a2_y[i]]
+                    for i in range(len(new_a1_y))
+                ]
+            )
             self.spline = interp1d(temp_curve[:, 0], temp_curve[:, 1])
             self.curve = self.spline(x_range)
 
@@ -1260,7 +1517,7 @@ def interpolate_data(self, raw_data, calib_wavelengths):
             self.spline = spline630
 
         else:
-            raise ValueError(f'Wavelength {self.wavelength} not understood')
+            raise ValueError(f"Wavelength {self.wavelength} not understood")
 
     def get_voltage(self, retardance):
         """
@@ -1277,19 +1534,21 @@ def get_voltage(self, retardance):
 
         """
 
-        retardance = np.asarray(retardance, dtype='double')
+        retardance = np.asarray(retardance, dtype="double")
         voltage = None
-        ret_nanometers = retardance*self.wavelength
+        ret_nanometers = retardance * self.wavelength
 
         if retardance < self.ret_min:
             voltage = self.V_max
         elif retardance > self.ret_max:
             voltage = self.V_min
         else:
-            if self.interp_method == 'linear':
+            if self.interp_method == "linear":
                 voltage = np.abs(self.curve - ret_nanometers).argmin() / 1000
-            elif self.interp_method == 'schnoor_fit':
-                voltage = self.schnoor_fit_inv(ret_nanometers, *self.fit_params, self.wavelength)
+            elif self.interp_method == "schnoor_fit":
+                voltage = self.schnoor_fit_inv(
+                    ret_nanometers, *self.fit_params, self.wavelength
+                )
 
         return voltage
 
@@ -1308,21 +1567,25 @@ def get_retardance(self, volts):
 
         """
 
-        volts = np.asarray(volts, dtype='double')
+        volts = np.asarray(volts, dtype="double")
         ret_nanometers = None
 
         if volts < self.V_min:
             volts = self.V_min
         elif volts >= self.V_max:
-            if self.interp_method == 'linear':
-                volts = self.V_max - 1e-3   # interpolation breaks down at upper boundary
+            if self.interp_method == "linear":
+                volts = (
+                    self.V_max - 1e-3
+                )  # interpolation breaks down at upper boundary
             else:
                 volts = self.V_max
 
-        if self.interp_method == 'linear':
+        if self.interp_method == "linear":
             ret_nanometers = self.spline(volts * 1000)
-        elif self.interp_method == 'schnoor_fit':
-            ret_nanometers = self.schnoor_fit(volts, *self.fit_params, self.wavelength)
+        elif self.interp_method == "schnoor_fit":
+            ret_nanometers = self.schnoor_fit(
+                volts, *self.fit_params, self.wavelength
+            )
         retardance = ret_nanometers / self.wavelength
 
         return retardance
diff --git a/recOrder/calib/Optimization.py b/recOrder/calib/Optimization.py
index 88ea8933..6e6893b0 100644
--- a/recOrder/calib/Optimization.py
+++ b/recOrder/calib/Optimization.py
@@ -3,68 +3,104 @@
 from recOrder.io.core_functions import snap_and_average
 import logging
 
-class BrentOptimizer:
 
+class BrentOptimizer:
     def __init__(self, calib):
 
         self.calib = calib
 
-
     def _check_bounds(self, lca_bound, lcb_bound):
 
-        current_lca = self.calib.get_lc('LCA')
-        current_lcb = self.calib.get_lc('LCB')
+        current_lca = self.calib.get_lc("LCA")
+        current_lcb = self.calib.get_lc("LCB")
 
         # check that bounds don't exceed range of LC
-        lca_lower_bound = 0.01 if (current_lca - lca_bound) <= 0.01 else current_lca - lca_bound
-        lca_upper_bound = 1.6 if (current_lca + lca_bound) >= 1.6 else current_lca + lca_bound
-
-        lcb_lower_bound = 0.01 if current_lcb - lcb_bound <= 0.01 else current_lcb - lcb_bound
-        lcb_upper_bound = 1.6 if current_lcb + lcb_bound >= 1.6 else current_lcb + lcb_bound
-
-        return lca_lower_bound, lca_upper_bound, lcb_lower_bound, lcb_upper_bound
-
-    def opt_lca(self, cost_function, lower_bound, upper_bound, reference, cost_function_args):
-
-        xopt, fval, ierr, numfunc = optimize.fminbound(cost_function,
-                                                       x1=lower_bound,
-                                                       x2=upper_bound,
-                                                       disp=0,
-                                                       args=cost_function_args,
-                                                       full_output=True)
+        lca_lower_bound = (
+            0.01
+            if (current_lca - lca_bound) <= 0.01
+            else current_lca - lca_bound
+        )
+        lca_upper_bound = (
+            1.6
+            if (current_lca + lca_bound) >= 1.6
+            else current_lca + lca_bound
+        )
+
+        lcb_lower_bound = (
+            0.01
+            if current_lcb - lcb_bound <= 0.01
+            else current_lcb - lcb_bound
+        )
+        lcb_upper_bound = (
+            1.6 if current_lcb + lcb_bound >= 1.6 else current_lcb + lcb_bound
+        )
+
+        return (
+            lca_lower_bound,
+            lca_upper_bound,
+            lcb_lower_bound,
+            lcb_upper_bound,
+        )
+
+    def opt_lca(
+        self,
+        cost_function,
+        lower_bound,
+        upper_bound,
+        reference,
+        cost_function_args,
+    ):
+
+        xopt, fval, ierr, numfunc = optimize.fminbound(
+            cost_function,
+            x1=lower_bound,
+            x2=upper_bound,
+            disp=0,
+            args=cost_function_args,
+            full_output=True,
+        )
 
         lca = xopt
-        lcb = self.calib.get_lc(self.calib.mmc, self.calib.PROPERTIES['LCA'])
+        lcb = self.calib.get_lc(self.calib.mmc, self.calib.PROPERTIES["LCA"])
         abs_intensity = fval + reference
         difference = fval / reference * 100
 
-        logging.debug('\tOptimize lca ...')
+        logging.debug("\tOptimize lca ...")
         logging.debug(f"\tlca = {lca:.5f}")
         logging.debug(f"\tlcb = {lcb:.5f}")
-        logging.debug(f'\tIntensity = {abs_intensity}')
-        logging.debug(f'\tIntensity Difference = {difference:.4f}%')
+        logging.debug(f"\tIntensity = {abs_intensity}")
+        logging.debug(f"\tIntensity Difference = {difference:.4f}%")
 
         return [lca, lcb, abs_intensity, difference]
 
-    def opt_lcb(self, cost_function, lower_bound, upper_bound, reference, cost_function_args):
-
-        xopt, fval, ierr, numfunc = optimize.fminbound(cost_function,
-                                                       x1=lower_bound,
-                                                       x2=upper_bound,
-                                                       disp=0,
-                                                       args=cost_function_args,
-                                                       full_output=True)
-
-        lca = self.calib.get_lc(self.calib.mmc, self.calib.PROPERTIES['LCA'])
+    def opt_lcb(
+        self,
+        cost_function,
+        lower_bound,
+        upper_bound,
+        reference,
+        cost_function_args,
+    ):
+
+        xopt, fval, ierr, numfunc = optimize.fminbound(
+            cost_function,
+            x1=lower_bound,
+            x2=upper_bound,
+            disp=0,
+            args=cost_function_args,
+            full_output=True,
+        )
+
+        lca = self.calib.get_lc(self.calib.mmc, self.calib.PROPERTIES["LCA"])
         lcb = xopt
         abs_intensity = fval + reference
         difference = fval / reference * 100
 
-        logging.debug('\tOptimize lcb ...')
+        logging.debug("\tOptimize lcb ...")
         logging.debug(f"\tlca = {lca:.5f}")
         logging.debug(f"\tlcb = {lcb:.5f}")
-        logging.debug(f'\tIntensity = {abs_intensity}')
-        logging.debug(f'\tIntensity Difference = {difference:.4f}%')
+        logging.debug(f"\tIntensity = {abs_intensity}")
+        logging.debug(f"\tIntensity Difference = {difference:.4f}%")
 
         return [lca, lcb, abs_intensity, difference]
 
@@ -76,40 +112,64 @@ def optimize(self, state, lca_bound, lcb_bound, reference, thresh, n_iter):
         optimal = []
 
         while not converged:
-            logging.debug(f'iteration: {iteration}')
+            logging.debug(f"iteration: {iteration}")
 
-            lca_lower_bound, lca_upper_bound,\
-            lcb_lower_bound, lcb_upper_bound = self._check_bounds(lca_bound, lcb_bound)
+            (
+                lca_lower_bound,
+                lca_upper_bound,
+                lcb_lower_bound,
+                lcb_upper_bound,
+            ) = self._check_bounds(lca_bound, lcb_bound)
 
-            if state == 'ext':
+            if state == "ext":
 
-                results_lca = self.opt_lca(self.calib.opt_lc, lca_lower_bound, lca_upper_bound,
-                                            reference, (self.calib.PROPERTIES['LCA'], reference))
+                results_lca = self.opt_lca(
+                    self.calib.opt_lc,
+                    lca_lower_bound,
+                    lca_upper_bound,
+                    reference,
+                    (self.calib.PROPERTIES["LCA"], reference),
+                )
 
-                self.calib.set_lc(self.calib.mmc, results_lca[0], 'LCA')
+                self.calib.set_lc(self.calib.mmc, results_lca[0], "LCA")
 
                 optimal.append(results_lca)
 
-                results_lcb = self.opt_lcb(self.calib.opt_lc, lcb_lower_bound, lcb_upper_bound,
-                                            reference, (self.calib.PROPERTIES['LCB'], reference))
+                results_lcb = self.opt_lcb(
+                    self.calib.opt_lc,
+                    lcb_lower_bound,
+                    lcb_upper_bound,
+                    reference,
+                    (self.calib.PROPERTIES["LCB"], reference),
+                )
 
-                self.calib.set_lc(self.calib.mmc, results_lca[1], 'LCB')
+                self.calib.set_lc(self.calib.mmc, results_lca[1], "LCB")
 
                 optimal.append(results_lcb)
 
                 results = results_lcb
 
-            if state == '45' or state == '135':
+            if state == "45" or state == "135":
 
-                results = self.opt_lcb(self.calib.opt_lc, lca_lower_bound, lca_upper_bound,
-                                        reference, (self.calib.PROPERTIES['LCB'], reference))
+                results = self.opt_lcb(
+                    self.calib.opt_lc,
+                    lca_lower_bound,
+                    lca_upper_bound,
+                    reference,
+                    (self.calib.PROPERTIES["LCB"], reference),
+                )
 
                 optimal.append(results)
 
-            if state == '60':
+            if state == "60":
 
-                results = self.opt_lca(self.calib.opt_lc_cons, lca_lower_bound, lca_upper_bound,
-                                        reference, (reference, '60'))
+                results = self.opt_lca(
+                    self.calib.opt_lc_cons,
+                    lca_lower_bound,
+                    lca_upper_bound,
+                    reference,
+                    (reference, "60"),
+                )
 
                 swing = (self.calib.lca_ext - results[0]) * self.calib.ratio
                 lca = results[0]
@@ -117,16 +177,26 @@ def optimize(self, state, lca_bound, lcb_bound, reference, thresh, n_iter):
 
                 optimal.append([lca, lcb, results[2], results[3]])
 
-            if state == '90':
+            if state == "90":
 
-                results = self.opt_lca(self.calib.opt_lc, lca_lower_bound, lca_upper_bound,
-                                           reference, (self.calib.PROPERTIES['LCA'], reference))
+                results = self.opt_lca(
+                    self.calib.opt_lc,
+                    lca_lower_bound,
+                    lca_upper_bound,
+                    reference,
+                    (self.calib.PROPERTIES["LCA"], reference),
+                )
 
                 optimal.append(results)
 
-            if state == '120':
-                results = self.opt_lca(self.calib.opt_lc_cons, lca_lower_bound, lca_upper_bound,
-                                       reference, (reference, '120'))
+            if state == "120":
+                results = self.opt_lca(
+                    self.calib.opt_lc_cons,
+                    lca_lower_bound,
+                    lca_upper_bound,
+                    reference,
+                    (reference, "120"),
+                )
 
                 swing = (self.calib.lca_ext - results[0]) * self.calib.ratio
                 lca = results[0]
@@ -143,13 +213,17 @@ def optimize(self, state, lca_bound, lcb_bound, reference, thresh, n_iter):
 
             # if loop preforms more than n_iter iterations, stop
             elif iteration >= n_iter:
-                logging.debug(f'Exceeded {n_iter} Iterations: Search discontinuing')
+                logging.debug(
+                    f"Exceeded {n_iter} Iterations: Search discontinuing"
+                )
 
                 converged = True
                 optimal = np.asarray(optimal)
                 opt = np.where(optimal == np.min(np.abs(optimal[:, 0])))[0]
 
-                logging.debug(f'Lowest Inten: {optimal[opt, 0]}, lca = {optimal[opt, 1]}, lcb = {optimal[opt, 2]}')
+                logging.debug(
+                    f"Lowest Inten: {optimal[opt, 0]}, lca = {optimal[opt, 1]}, lcb = {optimal[opt, 2]}"
+                )
 
                 return optimal[-1, 0], optimal[-1, 1], optimal[-1, 2]
 
@@ -157,110 +231,195 @@ def optimize(self, state, lca_bound, lcb_bound, reference, thresh, n_iter):
 
 
 class MinScalarOptimizer:
-
     def __init__(self, calib):
 
         self.calib = calib
 
     def _check_bounds(self, lca_bound, lcb_bound):
 
-        current_lca = self.calib.get_lc('LCA')
-        current_lcb = self.calib.get_lc('LCB')
+        current_lca = self.calib.get_lc("LCA")
+        current_lcb = self.calib.get_lc("LCB")
 
-        if self.calib.mode == 'voltage':
+        if self.calib.mode == "voltage":
             # check that bounds don't exceed range of LC
-            lca_lower_bound = 0.01 if (current_lca - lca_bound) <= 0.01 else current_lca - lca_bound
-            lca_upper_bound = 2.2 if (current_lca + lca_bound) >= 2.2 else current_lca + lca_bound
-
-            lcb_lower_bound = 0.01 if current_lcb - lcb_bound <= 0.01 else current_lcb - lcb_bound
-            lcb_upper_bound = 2.2 if current_lcb + lcb_bound >= 2.2 else current_lcb + lcb_bound
+            lca_lower_bound = (
+                0.01
+                if (current_lca - lca_bound) <= 0.01
+                else current_lca - lca_bound
+            )
+            lca_upper_bound = (
+                2.2
+                if (current_lca + lca_bound) >= 2.2
+                else current_lca + lca_bound
+            )
+
+            lcb_lower_bound = (
+                0.01
+                if current_lcb - lcb_bound <= 0.01
+                else current_lcb - lcb_bound
+            )
+            lcb_upper_bound = (
+                2.2
+                if current_lcb + lcb_bound >= 2.2
+                else current_lcb + lcb_bound
+            )
 
         else:
             # check that bounds don't exceed range of LC
-            lca_lower_bound = 0.01 if (current_lca - lca_bound) <= 0.01 else current_lca - lca_bound
-            lca_upper_bound = 1.6 if (current_lca + lca_bound) >= 1.6 else current_lca + lca_bound
-
-            lcb_lower_bound = 0.01 if current_lcb - lcb_bound <= 0.01 else current_lcb - lcb_bound
-            lcb_upper_bound = 1.6 if current_lcb + lcb_bound >= 1.6 else current_lcb + lcb_bound
-
-        return lca_lower_bound, lca_upper_bound, lcb_lower_bound, lcb_upper_bound
-
-    def opt_lca(self, cost_function, lower_bound, upper_bound, reference, cost_function_args):
-
-        res = optimize.minimize_scalar(cost_function, bounds=(lower_bound, upper_bound),
-                                       method='bounded', args=cost_function_args)
+            lca_lower_bound = (
+                0.01
+                if (current_lca - lca_bound) <= 0.01
+                else current_lca - lca_bound
+            )
+            lca_upper_bound = (
+                1.6
+                if (current_lca + lca_bound) >= 1.6
+                else current_lca + lca_bound
+            )
+
+            lcb_lower_bound = (
+                0.01
+                if current_lcb - lcb_bound <= 0.01
+                else current_lcb - lcb_bound
+            )
+            lcb_upper_bound = (
+                1.6
+                if current_lcb + lcb_bound >= 1.6
+                else current_lcb + lcb_bound
+            )
+
+        return (
+            lca_lower_bound,
+            lca_upper_bound,
+            lcb_lower_bound,
+            lcb_upper_bound,
+        )
+
+    def opt_lca(
+        self,
+        cost_function,
+        lower_bound,
+        upper_bound,
+        reference,
+        cost_function_args,
+    ):
+
+        res = optimize.minimize_scalar(
+            cost_function,
+            bounds=(lower_bound, upper_bound),
+            method="bounded",
+            args=cost_function_args,
+        )
 
         lca = res.x
-        lcb = self.calib.get_lc('LCB')
+        lcb = self.calib.get_lc("LCB")
         abs_intensity = res.fun + reference
         difference = res.fun / reference * 100
 
-        logging.debug('\tOptimize lca ...')
+        logging.debug("\tOptimize lca ...")
         logging.debug(f"\tlca = {lca:.5f}")
         logging.debug(f"\tlcb = {lcb:.5f}")
-        logging.debug(f'\tIntensity = {abs_intensity}')
-        logging.debug(f'\tIntensity Difference = {difference:.4f}%')
+        logging.debug(f"\tIntensity = {abs_intensity}")
+        logging.debug(f"\tIntensity Difference = {difference:.4f}%")
 
         return [lca, lcb, abs_intensity, difference]
 
-    def opt_lcb(self, cost_function, lower_bound, upper_bound, reference, cost_function_args):
-
-        res = optimize.minimize_scalar(cost_function, bounds=(lower_bound, upper_bound),
-                                       method='bounded', args=cost_function_args)
-
-        lca = self.calib.get_lc('LCA')
+    def opt_lcb(
+        self,
+        cost_function,
+        lower_bound,
+        upper_bound,
+        reference,
+        cost_function_args,
+    ):
+
+        res = optimize.minimize_scalar(
+            cost_function,
+            bounds=(lower_bound, upper_bound),
+            method="bounded",
+            args=cost_function_args,
+        )
+
+        lca = self.calib.get_lc("LCA")
         lcb = res.x
         abs_intensity = res.fun + reference
         difference = res.fun / reference * 100
 
-        logging.debug('\tOptimize lcb ...')
+        logging.debug("\tOptimize lcb ...")
         logging.debug(f"\tlca = {lca:.5f}")
         logging.debug(f"\tlcb = {lcb:.5f}")
-        logging.debug(f'\tIntensity = {abs_intensity}')
-        logging.debug(f'\tIntensity Difference = {difference:.4f}%')
+        logging.debug(f"\tIntensity = {abs_intensity}")
+        logging.debug(f"\tIntensity Difference = {difference:.4f}%")
 
         return [lca, lcb, abs_intensity, difference]
 
-    def optimize(self, state, lca_bound, lcb_bound, reference, thresh=None, n_iter=None):
+    def optimize(
+        self, state, lca_bound, lcb_bound, reference, thresh=None, n_iter=None
+    ):
 
-        lca_lower_bound, lca_upper_bound, lcb_lower_bound, lcb_upper_bound = self._check_bounds(lca_bound, lcb_bound)
+        (
+            lca_lower_bound,
+            lca_upper_bound,
+            lcb_lower_bound,
+            lcb_upper_bound,
+        ) = self._check_bounds(lca_bound, lcb_bound)
 
-        if state == 'ext':
+        if state == "ext":
             optimal = []
 
-            results_lca = self.opt_lca(self.calib.opt_lc, lca_lower_bound, lca_upper_bound,
-                                       reference, ('LCA', reference))
+            results_lca = self.opt_lca(
+                self.calib.opt_lc,
+                lca_lower_bound,
+                lca_upper_bound,
+                reference,
+                ("LCA", reference),
+            )
 
-            self.calib.set_lc(results_lca[0], 'LCA')
+            self.calib.set_lc(results_lca[0], "LCA")
 
             optimal.append(results_lca)
 
-            results_lcb = self.opt_lcb(self.calib.opt_lc, lcb_lower_bound, lcb_upper_bound,
-                                       reference, ('LCB', reference))
+            results_lcb = self.opt_lcb(
+                self.calib.opt_lc,
+                lcb_lower_bound,
+                lcb_upper_bound,
+                reference,
+                ("LCB", reference),
+            )
 
-            self.calib.set_lc(results_lcb[1], 'LCB')
+            self.calib.set_lc(results_lcb[1], "LCB")
 
             optimal.append(results_lcb)
 
             # ============BEGIN FINE SEARCH=================
 
-            logging.debug(f'\n\tBeginning Finer Search\n')
-            lca_lower_bound = results_lcb[0] - .01
-            lca_upper_bound = results_lcb[0] + .01
-            lcb_lower_bound = results_lcb[1] - .01
-            lcb_upper_bound = results_lcb[1] + .01
+            logging.debug(f"\n\tBeginning Finer Search\n")
+            lca_lower_bound = results_lcb[0] - 0.01
+            lca_upper_bound = results_lcb[0] + 0.01
+            lcb_lower_bound = results_lcb[1] - 0.01
+            lcb_upper_bound = results_lcb[1] + 0.01
 
-            results_lca = self.opt_lca(self.calib.opt_lc, lca_lower_bound, lca_upper_bound,
-                                       reference, ('LCA', reference))
+            results_lca = self.opt_lca(
+                self.calib.opt_lc,
+                lca_lower_bound,
+                lca_upper_bound,
+                reference,
+                ("LCA", reference),
+            )
 
-            self.calib.set_lc(results_lca[0], 'LCA')
+            self.calib.set_lc(results_lca[0], "LCA")
 
             optimal.append(results_lca)
 
-            results_lcb = self.opt_lcb(self.calib.opt_lc, lcb_lower_bound, lcb_upper_bound,
-                                       reference, ('LCB', reference))
+            results_lcb = self.opt_lcb(
+                self.calib.opt_lc,
+                lcb_lower_bound,
+                lcb_upper_bound,
+                reference,
+                ("LCB", reference),
+            )
 
-            self.calib.set_lc(results_lcb[1], 'LCB')
+            self.calib.set_lc(results_lcb[1], "LCB")
 
             optimal.append(results_lcb)
 
@@ -273,30 +432,50 @@ def optimize(self, state, lca_bound, lcb_bound, reference, thresh=None, n_iter=N
             lcb = float(optimal[opt][0][1])
             results = optimal[opt][0]
 
-        if state == '45' or state == '135':
-            results = self.opt_lcb(self.calib.opt_lc, lcb_lower_bound, lcb_upper_bound,
-                                   reference, ('LCB', reference))
+        if state == "45" or state == "135":
+            results = self.opt_lcb(
+                self.calib.opt_lc,
+                lcb_lower_bound,
+                lcb_upper_bound,
+                reference,
+                ("LCB", reference),
+            )
 
             lca = results[0]
             lcb = results[1]
 
-        if state == '60':
-            results = self.opt_lca(self.calib.opt_lc_cons, lca_lower_bound, lca_upper_bound,
-                                   reference, ('LCA', reference, '60'))
+        if state == "60":
+            results = self.opt_lca(
+                self.calib.opt_lc_cons,
+                lca_lower_bound,
+                lca_upper_bound,
+                reference,
+                ("LCA", reference, "60"),
+            )
 
             swing = (self.calib.lca_ext - results[0]) * self.calib.ratio
             lca = results[0]
             lcb = self.calib.lcb_ext + swing
 
-        if state == '90':
-            results = self.opt_lca(self.calib.opt_lc, lca_lower_bound, lca_upper_bound,
-                                       reference, ('LCA', reference))
+        if state == "90":
+            results = self.opt_lca(
+                self.calib.opt_lc,
+                lca_lower_bound,
+                lca_upper_bound,
+                reference,
+                ("LCA", reference),
+            )
             lca = results[0]
             lcb = results[1]
 
-        if state == '120':
-            results = self.opt_lca(self.calib.opt_lc_cons, lca_lower_bound, lca_upper_bound,
-                                   reference, ('LCB', reference, '120'))
+        if state == "120":
+            results = self.opt_lca(
+                self.calib.opt_lc_cons,
+                lca_lower_bound,
+                lca_upper_bound,
+                reference,
+                ("LCB", reference, "120"),
+            )
 
             swing = (self.calib.lca_ext - results[0]) * self.calib.ratio
             lca = results[0]
diff --git a/recOrder/compute/__init__.py b/recOrder/compute/__init__.py
index 62937c77..d4cc5512 100644
--- a/recOrder/compute/__init__.py
+++ b/recOrder/compute/__init__.py
@@ -1,1 +1,1 @@
-from .qlipp_compute import *
\ No newline at end of file
+from .qlipp_compute import *
diff --git a/recOrder/compute/qlipp_compute.py b/recOrder/compute/qlipp_compute.py
index ad009307..e99b0c2a 100644
--- a/recOrder/compute/qlipp_compute.py
+++ b/recOrder/compute/qlipp_compute.py
@@ -3,10 +3,25 @@
 import time
 
 
-def initialize_reconstructor(pipeline, image_dim=None, wavelength_nm=None, swing=None, calibration_scheme=None,
-                             NA_obj=None, NA_illu=None, mag=None, n_slices=None, z_step_um=None,
-                             pad_z=0, pixel_size_um=None, bg_correction='local_fit', n_obj_media=1.0, mode='3D',
-                             use_gpu=False, gpu_id=0):
+def initialize_reconstructor(
+    pipeline,
+    image_dim=None,
+    wavelength_nm=None,
+    swing=None,
+    calibration_scheme=None,
+    NA_obj=None,
+    NA_illu=None,
+    mag=None,
+    n_slices=None,
+    z_step_um=None,
+    pad_z=0,
+    pixel_size_um=None,
+    bg_correction="local_fit",
+    n_obj_media=1.0,
+    mode="3D",
+    use_gpu=False,
+    gpu_id=0,
+):
     """
     Initialize the QLIPP reconstructor for downstream tasks. See tags next to parameters
     for which parameters are needed for each pipeline
@@ -74,76 +89,100 @@ def initialize_reconstructor(pipeline, image_dim=None, wavelength_nm=None, swing
             reconstructor     : object
                                 reconstruction object initialized with reconstruction parameters
 
-        """
+    """
 
     anisotropy_only = False
 
-    if pipeline == 'QLIPP' or pipeline == 'PhaseFromBF':
+    if pipeline == "QLIPP" or pipeline == "PhaseFromBF":
 
         if not NA_obj:
-            raise ValueError('Please specify NA_obj in function parameters')
+            raise ValueError("Please specify NA_obj in function parameters")
         if not NA_illu:
-            raise ValueError('Please specify NA_illu in function parameters')
+            raise ValueError("Please specify NA_illu in function parameters")
         if not mag:
-            raise ValueError('Please specify mag (magnification) in function parameters')
+            raise ValueError(
+                "Please specify mag (magnification) in function parameters"
+            )
         if not wavelength_nm:
-            raise ValueError('Please specify the wavelength for reconstruction')
+            raise ValueError(
+                "Please specify the wavelength for reconstruction"
+            )
         if not n_slices:
-            raise ValueError('Please specify n_slices in function parameters')
+            raise ValueError("Please specify n_slices in function parameters")
         if not z_step_um:
-            raise ValueError('Please specify z_step_um in function parameters')
+            raise ValueError("Please specify z_step_um in function parameters")
         if not pixel_size_um:
-            raise ValueError('Please specify NA_obj in function parameters')
+            raise ValueError("Please specify NA_obj in function parameters")
         if not n_obj_media:
-            raise ValueError('Please specify NA_obj in function parameters')
+            raise ValueError("Please specify NA_obj in function parameters")
         if not image_dim:
-            raise ValueError('Please specify image_dim in function parameters')
+            raise ValueError("Please specify image_dim in function parameters")
 
-        if pipeline == 'QLIPP':
+        if pipeline == "QLIPP":
             if not calibration_scheme:
-                raise ValueError('Please specify qlipp_scheme (calibration scheme) for QLIPP reconstruction')
+                raise ValueError(
+                    "Please specify qlipp_scheme (calibration scheme) for QLIPP reconstruction"
+                )
             if not swing:
-                raise ValueError('Please specify swing in function parameters')
+                raise ValueError("Please specify swing in function parameters")
 
-    elif pipeline == 'birefringence':
+    elif pipeline == "birefringence":
 
         anisotropy_only = True
 
         if not calibration_scheme:
-            raise ValueError('Please specify qlipp_scheme (calibration scheme) for QLIPP reconstruction')
+            raise ValueError(
+                "Please specify qlipp_scheme (calibration scheme) for QLIPP reconstruction"
+            )
         if not wavelength_nm:
-            raise ValueError('Please specify the wavelength for QLIPP reconstruction')
+            raise ValueError(
+                "Please specify the wavelength for QLIPP reconstruction"
+            )
         if not swing:
-            raise ValueError('Please specify swing in function parameters')
+            raise ValueError("Please specify swing in function parameters")
 
     else:
-        raise ValueError(f'Pipeline {pipeline} not understood')
+        raise ValueError(f"Pipeline {pipeline} not understood")
 
     # Modify user inputs to fit waveorder input requirements
     lambda_illu = wavelength_nm / 1000 if wavelength_nm else None
     n_defocus = n_slices if n_slices else 0
     z_step_um = 0 if not z_step_um else z_step_um
-    z_defocus = -(np.r_[:n_defocus] - n_defocus // 2) * z_step_um # assumes stack starts from the bottom
+    z_defocus = (
+        -(np.r_[:n_defocus] - n_defocus // 2) * z_step_um
+    )  # assumes stack starts from the bottom
     ps = pixel_size_um / mag if pixel_size_um else None
     cali = True
     NA_obj = 0 if not NA_obj else NA_obj
     NA_illu = 0 if not NA_illu else NA_illu
 
-    if calibration_scheme == '4-State':
-        inst_mat = np.array([[1, 0, 0, -1],
-                             [1, np.sin(2 * np.pi * swing), 0, -np.cos(2 * np.pi * swing)],
-                             [1, -0.5 * np.sin(2 * np.pi * swing), np.sqrt(3) * np.cos(np.pi * swing) * np.sin(np.pi * swing),
-                              -np.cos(2 * np.pi * swing)],
-                             [1, -0.5 * np.sin(2 * np.pi * swing), -np.sqrt(3) / 2 * np.sin(2 * np.pi * swing),
-                              -np.cos(2 * np.pi * swing)]])
+    if calibration_scheme == "4-State":
+        inst_mat = np.array(
+            [
+                [1, 0, 0, -1],
+                [1, np.sin(2 * np.pi * swing), 0, -np.cos(2 * np.pi * swing)],
+                [
+                    1,
+                    -0.5 * np.sin(2 * np.pi * swing),
+                    np.sqrt(3) * np.cos(np.pi * swing) * np.sin(np.pi * swing),
+                    -np.cos(2 * np.pi * swing),
+                ],
+                [
+                    1,
+                    -0.5 * np.sin(2 * np.pi * swing),
+                    -np.sqrt(3) / 2 * np.sin(2 * np.pi * swing),
+                    -np.cos(2 * np.pi * swing),
+                ],
+            ]
+        )
         n_channel = 4
 
-    elif calibration_scheme == '5-State':
+    elif calibration_scheme == "5-State":
         swing = swing * 2 * np.pi
         inst_mat = None
         n_channel = 5
 
-    elif calibration_scheme == 'PhaseFromBF':
+    elif calibration_scheme == "PhaseFromBF":
         inst_mat = None
         n_channel = 1
         swing = 0
@@ -152,34 +191,37 @@ def initialize_reconstructor(pipeline, image_dim=None, wavelength_nm=None, swing
         n_channel = 1
         swing = 0
 
-    print('Initializing Reconstructor...')
+    print("Initializing Reconstructor...")
     start_time = time.time()
     print(bg_correction)
-    recon = waveorder_microscopy(img_dim=image_dim,
-                                 lambda_illu=lambda_illu,
-                                 ps=ps,
-                                 NA_obj=NA_obj,
-                                 NA_illu=NA_illu,
-                                 z_defocus=z_defocus,
-                                 chi=swing,
-                                 n_media=n_obj_media,
-                                 cali=cali,
-                                 bg_option=bg_correction,
-                                 A_matrix=inst_mat,
-                                 QLIPP_birefringence_only=anisotropy_only,
-                                 pad_z=pad_z,
-                                 phase_deconv=mode,
-                                 illu_mode='BF',
-                                 use_gpu=use_gpu,
-                                 gpu_id=gpu_id)
+    recon = waveorder_microscopy(
+        img_dim=image_dim,
+        lambda_illu=lambda_illu,
+        ps=ps,
+        NA_obj=NA_obj,
+        NA_illu=NA_illu,
+        z_defocus=z_defocus,
+        chi=swing,
+        n_media=n_obj_media,
+        cali=cali,
+        bg_option=bg_correction,
+        A_matrix=inst_mat,
+        QLIPP_birefringence_only=anisotropy_only,
+        pad_z=pad_z,
+        phase_deconv=mode,
+        illu_mode="BF",
+        use_gpu=use_gpu,
+        gpu_id=gpu_id,
+    )
 
     recon.N_channel = n_channel
 
     elapsed_time = (time.time() - start_time) / 60
-    print(f'Finished Initializing Reconstructor ({elapsed_time:0.2f} min)')
+    print(f"Finished Initializing Reconstructor ({elapsed_time:0.2f} min)")
 
     return recon
 
+
 def reconstruct_qlipp_stokes(data, recon, bg_stokes=None):
     """
     From intensity data, use the waveorder.waveorder_microscopy (recon) to build a stokes array
@@ -208,19 +250,24 @@ def reconstruct_qlipp_stokes(data, recon, bg_stokes=None):
     stokes_data = recon.Stokes_transform(stokes_data)
 
     # Don't do background correction if BG data isn't provided
-    if recon.bg_option == 'None':
-        return stokes_data # C(Z)YX
+    if recon.bg_option == "None":
+        return stokes_data  # C(Z)YX
 
     # Compute Stokes with background correction
     else:
         if len(np.shape(stokes_data)) == 4:
-            s_image = recon.Polscope_bg_correction(np.transpose(stokes_data, (-4, -2, -1, -3)), bg_stokes)
-            s_image = np.transpose(s_image, (0, 3, 1, 2)) # Tranpose to CZYX
+            s_image = recon.Polscope_bg_correction(
+                np.transpose(stokes_data, (-4, -2, -1, -3)), bg_stokes
+            )
+            s_image = np.transpose(s_image, (0, 3, 1, 2))  # Tranpose to CZYX
         else:
-            s_image = recon.Polscope_bg_correction(stokes_data, bg_stokes) # CYX
+            s_image = recon.Polscope_bg_correction(
+                stokes_data, bg_stokes
+            )  # CYX
 
         return s_image
 
+
 def reconstruct_qlipp_birefringence(stokes, recon):
     """
     From stokes data, use waveorder.waveorder_microscopy (recon) to build a birefringence array
@@ -245,16 +292,21 @@ def reconstruct_qlipp_birefringence(stokes, recon):
     elif stokes.ndim == 3:
         pass
     else:
-        raise ValueError(f'Incompatible stokes dimension: {stokes.shape}')
+        raise ValueError(f"Incompatible stokes dimension: {stokes.shape}")
 
     birefringence = recon.Polarization_recon(np.copy(stokes))
 
     # Return the transposed birefringence array with channel first
-    return np.transpose(birefringence, (-4, -1, -3, -2)) if len(birefringence.shape) == 4 else birefringence
+    return (
+        np.transpose(birefringence, (-4, -1, -3, -2))
+        if len(birefringence.shape) == 4
+        else birefringence
+    )
 
 
-def reconstruct_phase2D(S0, recon, method='Tikhonov', reg_p=1e-4, rho=1,
-                        lambda_p=1e-4, itr=50):
+def reconstruct_phase2D(
+    S0, recon, method="Tikhonov", reg_p=1e-4, rho=1, lambda_p=1e-4, itr=50
+):
     """
     Reconstruct 2D phase from a given S0 or BF stack.
 
@@ -275,13 +327,22 @@ def reconstruct_phase2D(S0, recon, method='Tikhonov', reg_p=1e-4, rho=1,
     """
 
     S0 = np.transpose(S0, (1, 2, 0))
-    _, phase2D = recon.Phase_recon(np.copy(S0).astype('float'), method=method, reg_p=reg_p, rho=rho, lambda_p=lambda_p, itr=itr, verbose=False)
+    _, phase2D = recon.Phase_recon(
+        np.copy(S0).astype("float"),
+        method=method,
+        reg_p=reg_p,
+        rho=rho,
+        lambda_p=lambda_p,
+        itr=itr,
+        verbose=False,
+    )
 
     return phase2D
 
 
-def reconstruct_phase3D(S0, recon, method='Tikhonov', reg_re=1e-4,
-                        rho=1e-3, lambda_re=1e-4, itr=50):
+def reconstruct_phase3D(
+    S0, recon, method="Tikhonov", reg_re=1e-4, rho=1e-3, lambda_re=1e-4, itr=50
+):
     """
     Reconstruct 2D phase from a given S0 or BF stack.
 
@@ -302,19 +363,36 @@ def reconstruct_phase3D(S0, recon, method='Tikhonov', reg_re=1e-4,
     """
 
     S0 = np.transpose(S0, (1, 2, 0))
-    phase3D = recon.Phase_recon_3D(np.copy(S0).astype('float'), method=method, reg_re=reg_re, rho=rho, lambda_re=lambda_re,
-                                   itr=itr, verbose=False)
+    phase3D = recon.Phase_recon_3D(
+        np.copy(S0).astype("float"),
+        method=method,
+        reg_re=reg_re,
+        rho=rho,
+        lambda_re=lambda_re,
+        itr=itr,
+        verbose=False,
+    )
 
     phase3D = np.transpose(phase3D, (-1, -3, -2))
 
     return phase3D
 
+
 class QLIPPBirefringenceCompute:
     """
     Convenience Class for computing QLIPP birefringence only.
     """
 
-    def __init__(self, shape, scheme, wavelength, swing, n_slices, bg_option, bg_data=None):
+    def __init__(
+        self,
+        shape,
+        scheme,
+        wavelength,
+        swing,
+        n_slices,
+        bg_option,
+        bg_data=None,
+    ):
 
         self.shape = shape
         self.scheme = scheme
@@ -323,16 +401,20 @@ def __init__(self, shape, scheme, wavelength, swing, n_slices, bg_option, bg_dat
         self.n_slices = n_slices
         self.bg_option = bg_option
 
-        self.reconstructor = initialize_reconstructor(pipeline='birefringence',
-                                                      image_dim=self.shape,
-                                                      calibration_scheme=self.scheme,
-                                                      wavelength_nm=self.wavelength,
-                                                      swing=self.swing,
-                                                      bg_correction=self.bg_option,
-                                                      n_slices=self.n_slices)
-
-        if bg_option != 'None':
-            self.bg_stokes = reconstruct_qlipp_stokes(bg_data, self.reconstructor)
+        self.reconstructor = initialize_reconstructor(
+            pipeline="birefringence",
+            image_dim=self.shape,
+            calibration_scheme=self.scheme,
+            wavelength_nm=self.wavelength,
+            swing=self.swing,
+            bg_correction=self.bg_option,
+            n_slices=self.n_slices,
+        )
+
+        if bg_option != "None":
+            self.bg_stokes = reconstruct_qlipp_stokes(
+                bg_data, self.reconstructor
+            )
         else:
             self.bg_stokes = None
 
@@ -350,8 +432,12 @@ def reconstruct(self, array):
                                     first channel is retardance [nm] second channel is orientation [0, pi]
 
         """
-        stokes = reconstruct_qlipp_stokes(array, self.reconstructor, self.bg_stokes)
-        birefringence = reconstruct_qlipp_birefringence(stokes, self.reconstructor)
+        stokes = reconstruct_qlipp_stokes(
+            array, self.reconstructor, self.bg_stokes
+        )
+        birefringence = reconstruct_qlipp_birefringence(
+            stokes, self.reconstructor
+        )
         birefringence[0] = birefringence[0] / (2 * np.pi) * self.wavelength
 
         return birefringence[0:2]
diff --git a/recOrder/io/__init__.py b/recOrder/io/__init__.py
index 2730cc46..58c8e239 100644
--- a/recOrder/io/__init__.py
+++ b/recOrder/io/__init__.py
@@ -1,4 +1,4 @@
 from .utils import *
 from .config_reader import ConfigReader
 from ._reader import napari_get_reader
-from .metadata_reader import MetadataReader
\ No newline at end of file
+from .metadata_reader import MetadataReader
diff --git a/recOrder/io/_reader.py b/recOrder/io/_reader.py
index 27466956..6df5c4bd 100644
--- a/recOrder/io/_reader.py
+++ b/recOrder/io/_reader.py
@@ -2,9 +2,10 @@
 import zarr
 from typing import Tuple, List, Dict, Union
 
+
 def napari_get_reader(path):
     if isinstance(path, str):
-        if '.zarr' in path:
+        if ".zarr" in path:
             return ome_zarr_reader
         else:
             return ome_tif_reader
@@ -12,29 +13,34 @@ def napari_get_reader(path):
         return None
 
 
-def ome_zarr_reader(path: Union[str, List[str]]) -> List[Tuple[zarr.Array, Dict]]:
+def ome_zarr_reader(
+    path: Union[str, List[str]]
+) -> List[Tuple[zarr.Array, Dict]]:
     reader = WaveorderReader(path)
     results = list()
 
-    zs = zarr.open(path, 'r')
+    zs = zarr.open(path, "r")
     names = []
 
     dict_ = zs.attrs.asdict()
-    wells = dict_['plate']['wells']
+    wells = dict_["plate"]["wells"]
     for well in wells:
-        path = well['path']
+        path = well["path"]
         well_dict = zs[path].attrs.asdict()
-        for name in well_dict['well']['images']:
-            names.append(name['path'])
+        for name in well_dict["well"]["images"]:
+            names.append(name["path"])
     for pos in range(reader.get_num_positions()):
         meta = dict()
         name = names[pos]
-        meta['name'] = name
+        meta["name"] = name
         results.append((reader.get_zarr(pos), meta))
 
     return results
 
-def ome_tif_reader(path: Union[str, List[str]]) -> List[Tuple[zarr.Array, Dict]]:
+
+def ome_tif_reader(
+    path: Union[str, List[str]]
+) -> List[Tuple[zarr.Array, Dict]]:
     reader = WaveorderReader(path)
     results = list()
 
@@ -42,9 +48,9 @@ def ome_tif_reader(path: Union[str, List[str]]) -> List[Tuple[zarr.Array, Dict]]
     for pos in range(npos):
         meta = dict()
         if npos == 1:
-            meta['name'] = 'Pos000_000'
+            meta["name"] = "Pos000_000"
         else:
-            meta['name'] = reader.stage_positions[pos]['Label'][2:]
+            meta["name"] = reader.stage_positions[pos]["Label"][2:]
         results.append((reader.get_zarr(pos), meta))
 
-    return results
\ No newline at end of file
+    return results
diff --git a/recOrder/io/config_reader.py b/recOrder/io/config_reader.py
index 5dd107cd..0744f94c 100644
--- a/recOrder/io/config_reader.py
+++ b/recOrder/io/config_reader.py
@@ -4,72 +4,81 @@
 import warnings
 
 DATASET = {
-    'method': None,
-    'mode': None,
-    'data_dir': None,
-    'save_dir': None,
-    'data_type': 'zarr',
-    'data_save_name': None,
-    'positions': 'all',
-    'timepoints': 'all',
-    'background': None,
-    'background_ROI': None,
-    'calibration_metadata': None
+    "method": None,
+    "mode": None,
+    "data_dir": None,
+    "save_dir": None,
+    "data_type": "zarr",
+    "data_save_name": None,
+    "positions": "all",
+    "timepoints": "all",
+    "background": None,
+    "background_ROI": None,
+    "calibration_metadata": None,
 }
 
 PROCESSING = {
-    'output_channels': None,
-    'qlipp_birefringence_only': False,
-    'background_correction': 'None',
-    'use_gpu': False,
-    'gpu_id': 0,
-    'wavelength': None,
-    'pixel_size': None,
-    'magnification': None,
-    'NA_objective': None,
-    'NA_condenser': None,
-    'n_objective_media': 1.003,
-    'brightfield_channel_index': 0,
-    'z_step': None,
-    'focus_zidx': None,
-    'reg': 1e-4,
-    'phase_denoiser_2D': 'Tikhonov',
-    'Tik_reg_abs_2D': 1e-4,
-    'Tik_reg_ph_2D': 1e-4,
-    'rho_2D': 1,
-    'itr_2D': 50,
-    'TV_reg_abs_2D': 1e-4,
-    'TV_reg_ph_2D': 1e-4,
-    'phase_denoiser_3D': 'Tikhonov',
-    'rho_3D': 1e-3,
-    'itr_3D': 50,
-    'Tik_reg_ph_3D': 1e-4,
-    'TV_reg_ph_3D': 5e-5,
-    'pad_z': 0
+    "output_channels": None,
+    "qlipp_birefringence_only": False,
+    "background_correction": "None",
+    "use_gpu": False,
+    "gpu_id": 0,
+    "wavelength": None,
+    "pixel_size": None,
+    "magnification": None,
+    "NA_objective": None,
+    "NA_condenser": None,
+    "n_objective_media": 1.003,
+    "brightfield_channel_index": 0,
+    "z_step": None,
+    "focus_zidx": None,
+    "reg": 1e-4,
+    "phase_denoiser_2D": "Tikhonov",
+    "Tik_reg_abs_2D": 1e-4,
+    "Tik_reg_ph_2D": 1e-4,
+    "rho_2D": 1,
+    "itr_2D": 50,
+    "TV_reg_abs_2D": 1e-4,
+    "TV_reg_ph_2D": 1e-4,
+    "phase_denoiser_3D": "Tikhonov",
+    "rho_3D": 1e-3,
+    "itr_3D": 50,
+    "Tik_reg_ph_3D": 1e-4,
+    "TV_reg_ph_3D": 5e-5,
+    "pad_z": 0,
 }
 
-class ConfigReader():
+
+class ConfigReader:
     """
     Config Reader handles all of the requirements necessary for running the pipeline.  Default values
     are used for those that do not need to be specified.  CLI will always overried config
 
     """
 
-    def __init__(self, cfg_path=None, data_dir=None, save_dir=None, method=None, mode=None, name=None, immutable=True):
+    def __init__(
+        self,
+        cfg_path=None,
+        data_dir=None,
+        save_dir=None,
+        method=None,
+        mode=None,
+        name=None,
+        immutable=True,
+    ):
 
         self.immutable = immutable
 
-
         if data_dir is not None:
-            setattr(self, 'data_dir', data_dir)
+            setattr(self, "data_dir", data_dir)
         if save_dir is not None:
-            setattr(self, 'save_dir', save_dir)
+            setattr(self, "save_dir", save_dir)
         if method is not None:
-            setattr(self, 'method', method)
+            setattr(self, "method", method)
         if mode is not None:
-            setattr(self, 'mode', mode)
+            setattr(self, "mode", mode)
         if name is not None:
-            setattr(self, 'data_save_name', name)
+            setattr(self, "data_save_name", name)
 
         # initialize defaults
         for key, value in DATASET.items():
@@ -87,7 +96,7 @@ def __init__(self, cfg_path=None, data_dir=None, save_dir=None, method=None, mod
             self.read_config(cfg_path, data_dir, save_dir, method, mode, name)
 
         # Create yaml dict to save in save_dir
-        setattr(self, 'yaml_dict', self._create_yaml_dict())
+        setattr(self, "yaml_dict", self._create_yaml_dict())
         # self._save_yaml()
 
     # Override set attribute function to disallow changes after init
@@ -100,54 +109,106 @@ def __setattr__(self, name, value):
     def _check_assertions(self, data_dir, save_dir, method, mode, name):
 
         # assert main fields of config
-        assert 'dataset' in self.config, \
-            'dataset is a required field in the config yaml file'
-        assert 'processing' in self.config, \
-            'processing is a required field in the config yaml file'
-
-        if not method: assert 'method' in self.config['dataset'], \
-            'Please provide method in config file or CLI argument'
-        if not mode: assert 'mode' in self.config['dataset'], \
-            'Please provide mode in config file or CLI argument'
-        if not data_dir: assert 'data_dir' in self.config['dataset'], \
-            'Please provide data_dir in config file or CLI argument'
-        if not save_dir: assert 'save_dir' in self.config['dataset'], \
-            'Please provide save_dir in config file or CLI argument'
-
-        if self.config['dataset']['positions'] != 'all' and not isinstance(self.config['dataset']['positions'], int):
-            assert isinstance(self.config['dataset']['positions'], list), \
-                'if not single integer value or "all", positions must be list (nested lists/tuples allowed)'
-        if self.config['dataset']['timepoints'] != 'all' and not isinstance(self.config['dataset']['timepoints'], int):
-            assert isinstance(self.config['dataset']['timepoints'], list), \
-                'if not single integer value or "all", timepoints must be list (nested lists/tuples allowed)'
-
-        for key,value in PROCESSING.items():
-            if key == 'output_channels':
-                if 'Phase3D' in self.config['processing'][key] or 'Phase2D' in self.config['processing'][key]:
-                    assert 'wavelength' in self.config['processing'], 'wavelength required for phase reconstruction'
-                    assert 'pixel_size' in self.config['processing'], 'pixel_size required for phase reconstruction'
-                    assert 'magnification' in self.config['processing'], 'magnification required for phase reconstruction'
-                    assert 'NA_objective' in self.config['processing'], 'NA_objective required for phase reconstruction'
-                    assert 'NA_condenser' in self.config['processing'], 'NA_condenser required for phase reconstruction'
-
-                if 'Phase3D' in self.config['processing'][key] and 'Phase2D' in self.config['processing'][key]:
-                    raise KeyError(f'Both Phase3D and Phase2D cannot be specified in {key}.  Please compute separately')
-
-                if 'Phase3D' in self.config['processing'][key] and self.config['dataset']['mode'] == '2D':
-                    raise KeyError(f'Specified mode is 2D and Phase3D was specified for reconstruction. '
-                                   'Only 2D reconstructions can be performed in 2D mode')
-
-                if 'Phase2D' in self.config['processing'][key] and self.config['dataset']['mode'] == '3D':
-                    raise KeyError(f'Specified mode is 3D and Phase2D was specified for reconstruction. '
-                                   'Only 3D reconstructions can be performed in 3D mode')
-
-            elif key == 'background_correction' and self.config['dataset']['method'] == 'QLIPP':
-                mode = self.config['processing'][key]
-                if mode == 'None' or mode == 'local_fit' or mode == 'local_fit+':
+        assert (
+            "dataset" in self.config
+        ), "dataset is a required field in the config yaml file"
+        assert (
+            "processing" in self.config
+        ), "processing is a required field in the config yaml file"
+
+        if not method:
+            assert (
+                "method" in self.config["dataset"]
+            ), "Please provide method in config file or CLI argument"
+        if not mode:
+            assert (
+                "mode" in self.config["dataset"]
+            ), "Please provide mode in config file or CLI argument"
+        if not data_dir:
+            assert (
+                "data_dir" in self.config["dataset"]
+            ), "Please provide data_dir in config file or CLI argument"
+        if not save_dir:
+            assert (
+                "save_dir" in self.config["dataset"]
+            ), "Please provide save_dir in config file or CLI argument"
+
+        if self.config["dataset"]["positions"] != "all" and not isinstance(
+            self.config["dataset"]["positions"], int
+        ):
+            assert isinstance(
+                self.config["dataset"]["positions"], list
+            ), 'if not single integer value or "all", positions must be list (nested lists/tuples allowed)'
+        if self.config["dataset"]["timepoints"] != "all" and not isinstance(
+            self.config["dataset"]["timepoints"], int
+        ):
+            assert isinstance(
+                self.config["dataset"]["timepoints"], list
+            ), 'if not single integer value or "all", timepoints must be list (nested lists/tuples allowed)'
+
+        for key, value in PROCESSING.items():
+            if key == "output_channels":
+                if (
+                    "Phase3D" in self.config["processing"][key]
+                    or "Phase2D" in self.config["processing"][key]
+                ):
+                    assert (
+                        "wavelength" in self.config["processing"]
+                    ), "wavelength required for phase reconstruction"
+                    assert (
+                        "pixel_size" in self.config["processing"]
+                    ), "pixel_size required for phase reconstruction"
+                    assert (
+                        "magnification" in self.config["processing"]
+                    ), "magnification required for phase reconstruction"
+                    assert (
+                        "NA_objective" in self.config["processing"]
+                    ), "NA_objective required for phase reconstruction"
+                    assert (
+                        "NA_condenser" in self.config["processing"]
+                    ), "NA_condenser required for phase reconstruction"
+
+                if (
+                    "Phase3D" in self.config["processing"][key]
+                    and "Phase2D" in self.config["processing"][key]
+                ):
+                    raise KeyError(
+                        f"Both Phase3D and Phase2D cannot be specified in {key}.  Please compute separately"
+                    )
+
+                if (
+                    "Phase3D" in self.config["processing"][key]
+                    and self.config["dataset"]["mode"] == "2D"
+                ):
+                    raise KeyError(
+                        f"Specified mode is 2D and Phase3D was specified for reconstruction. "
+                        "Only 2D reconstructions can be performed in 2D mode"
+                    )
+
+                if (
+                    "Phase2D" in self.config["processing"][key]
+                    and self.config["dataset"]["mode"] == "3D"
+                ):
+                    raise KeyError(
+                        f"Specified mode is 3D and Phase2D was specified for reconstruction. "
+                        "Only 3D reconstructions can be performed in 3D mode"
+                    )
+
+            elif (
+                key == "background_correction"
+                and self.config["dataset"]["method"] == "QLIPP"
+            ):
+                mode = self.config["processing"][key]
+                if (
+                    mode == "None"
+                    or mode == "local_fit"
+                    or mode == "local_fit+"
+                ):
                     pass
                 else:
-                    assert self.config['dataset']['background'] is not None, \
-                        'path to background data must be specified for this background correction method'
+                    assert (
+                        self.config["dataset"]["background"] is not None
+                    ), "path to background data must be specified for this background correction method"
 
     def save_yaml(self, dir_=None, name=None):
         self.immutable = False
@@ -155,84 +216,96 @@ def save_yaml(self, dir_=None, name=None):
         self.immutable = True
 
         dir_ = self.save_dir if dir_ is None else dir_
-        name = f'config_{self.data_save_name}.yml' if name is None else name
-        if not name.endswith('.yml'):
-            name += '.yml'
+        name = f"config_{self.data_save_name}.yml" if name is None else name
+        if not name.endswith(".yml"):
+            name += ".yml"
         if not os.path.exists(dir_):
             os.mkdir(dir_)
-        with open(os.path.join(dir_, name), 'w') as file:
+        with open(os.path.join(dir_, name), "w") as file:
             yaml.dump(self.yaml_dict, file)
         file.close()
 
     def _create_yaml_dict(self):
 
-        yaml_dict = {'dataset': {},
-                     'processing': {}}
+        yaml_dict = {"dataset": {}, "processing": {}}
 
         for key, value in DATASET.items():
-            yaml_dict['dataset'][key] = getattr(self, key)
+            yaml_dict["dataset"][key] = getattr(self, key)
 
         for key, value in PROCESSING.items():
-            yaml_dict['processing'][key] = getattr(self, key)
+            yaml_dict["processing"][key] = getattr(self, key)
 
         return yaml_dict
 
     def _use_default_name(self):
         path = pathlib.PurePath(self.data_dir)
-        super().__setattr__('data_save_name', path.name)
+        super().__setattr__("data_save_name", path.name)
 
     def _parse_dataset(self):
-        for key, value in self.config['dataset'].items():
+        for key, value in self.config["dataset"].items():
             if key in DATASET.keys():
 
                 # This section will prioritize the command line arguments over the
                 # config arguments (data_dir, save_dir, data_save_name)
-                if key == 'name' and self.data_save_name:
+                if key == "name" and self.data_save_name:
                     continue
-                elif key == 'data_dir' and self.data_dir:
+                elif key == "data_dir" and self.data_dir:
                     continue
-                elif key == 'save_dir' and self.save_dir:
+                elif key == "save_dir" and self.save_dir:
                     continue
-                elif key == 'mode' and self.mode:
+                elif key == "mode" and self.mode:
                     continue
-                elif key == 'method' and self.method:
+                elif key == "method" and self.method:
                     continue
 
                 # this section appends the rest of the dataset parameters specified
-                elif key == 'positions' or key == 'timepoints':
+                elif key == "positions" or key == "timepoints":
                     if isinstance(value, str):
-                        if value == 'all':
+                        if value == "all":
                             super().__setattr__(key, [value])
                         else:
-                            raise KeyError(f'{key} value {value} not understood,\
-                                       please specify a list or "all"')
+                            raise KeyError(
+                                f'{key} value {value} not understood,\
+                                       please specify a list or "all"'
+                            )
                     elif isinstance(value, int):
                         super().__setattr__(key, [value])
                     elif isinstance(value, tuple):
                         if len(value) == 2:
                             super().__setattr__(key, value)
                         else:
-                            raise KeyError(f'{key} value {value} is not a tuple with length of 2')
+                            raise KeyError(
+                                f"{key} value {value} is not a tuple with length of 2"
+                            )
                     elif isinstance(value, list):
                         super().__setattr__(key, value)
                     else:
-                        raise KeyError(f'{key} value {value} format not understood. \
-                                       Must be list with nested tuple or list or "all"')
+                        raise KeyError(
+                            f'{key} value {value} format not understood. \
+                                       Must be list with nested tuple or list or "all"'
+                        )
                 else:
                     super().__setattr__(key, value)
 
             else:
-                warnings.warn(f'yaml DATASET config field {key} is not recognized')
+                warnings.warn(
+                    f"yaml DATASET config field {key} is not recognized"
+                )
 
     def _parse_processing(self):
-        for key, value in self.config['processing'].items():
+        for key, value in self.config["processing"].items():
             if key in PROCESSING.keys():
                 super().__setattr__(key, value)
             else:
-                warnings.warn(f'yaml PROCESSING config field {key} is not recognized')
+                warnings.warn(
+                    f"yaml PROCESSING config field {key} is not recognized"
+                )
 
-        if 'Phase3D' not in self.output_channels and 'Phase2D' not in self.output_channels:
-            super().__setattr__('qlipp_birefringence_only', True)
+        if (
+            "Phase3D" not in self.output_channels
+            and "Phase2D" not in self.output_channels
+        ):
+            super().__setattr__("qlipp_birefringence_only", True)
 
     def read_config(self, cfg_path, data_dir, save_dir, method, mode, name):
 
@@ -244,6 +317,6 @@ def read_config(self, cfg_path, data_dir, save_dir, method, mode, name):
         self._check_assertions(data_dir, save_dir, method, mode, name)
         self._parse_dataset()
         self._parse_processing()
-        
+
         if not self.data_save_name:
             self._use_default_name()
diff --git a/recOrder/io/core_functions.py b/recOrder/io/core_functions.py
index 8c432512..2c12529b 100644
--- a/recOrder/io/core_functions.py
+++ b/recOrder/io/core_functions.py
@@ -18,7 +18,9 @@ def snap_image(mmc):
     """
 
     mmc.snapImage()
-    time.sleep(0.3) # sleep after snap to make sure the image we grab is the correct one
+    time.sleep(
+        0.3
+    )  # sleep after snap to make sure the image we grab is the correct one
 
     return mmc.getImage()
 
@@ -65,12 +67,16 @@ def snap_and_get_image(snap_manager):
 
     """
     snap_manager.snap(True)
-    time.sleep(0.3) # sleep after snap to make sure the image we grab is the correct one
+    time.sleep(
+        0.3
+    )  # sleep after snap to make sure the image we grab is the correct one
 
     # get pixels + dimensions
     height = snap_manager.getDisplay().getDisplayedImages().get(0).getHeight()
     width = snap_manager.getDisplay().getDisplayedImages().get(0).getWidth()
-    array = snap_manager.getDisplay().getDisplayedImages().get(0).getRawPixels()
+    array = (
+        snap_manager.getDisplay().getDisplayedImages().get(0).getRawPixels()
+    )
 
     return np.reshape(array, (height, width))
 
@@ -91,7 +97,9 @@ def snap_and_average(snap_manager, display=True):
     """
 
     snap_manager.snap(display)
-    time.sleep(0.3)  # sleep after snap to make sure the image we grab is the correct one
+    time.sleep(
+        0.3
+    )  # sleep after snap to make sure the image we grab is the correct one
 
     return snap_manager.getDisplay().getImagePlus().getStatistics().umean
 
@@ -117,11 +125,13 @@ def set_lc_waves(mmc, device_property: tuple, value: float):
     prop_name = device_property[1]
 
     if value > 1.6 or value < 0.001:
-        raise ValueError(f"Requested retardance value is {value} waves. "
-                         f"Retardance must be greater than 0.001 and less than 1.6 waves.")
+        raise ValueError(
+            f"Requested retardance value is {value} waves. "
+            f"Retardance must be greater than 0.001 and less than 1.6 waves."
+        )
 
     mmc.setProperty(device_name, prop_name, str(value))
-    time.sleep(20/1000)
+    time.sleep(20 / 1000)
 
 
 def set_lc_voltage(mmc, device_property: tuple, value: float):
@@ -145,8 +155,10 @@ def set_lc_voltage(mmc, device_property: tuple, value: float):
     prop_name = device_property[1]
 
     if value > 20.0 or value < 0.0:
-        raise ValueError(f"Requested LC voltage is {value} V. "
-                         f"LC voltage must be greater than 0.0 and less than 20.0 V.")
+        raise ValueError(
+            f"Requested LC voltage is {value} V. "
+            f"LC voltage must be greater than 0.0 and less than 20.0 V."
+        )
 
     mmc.setProperty(device_name, prop_name, str(value))
     time.sleep(20 / 1000)
@@ -173,7 +185,9 @@ def set_lc_daq(mmc, device_property: tuple, value: float):
     prop_name = device_property[1]
 
     if value > 5.0 or value < 0.0:
-        raise ValueError("DAC voltage must be greater than 0.0 and less than 5.0")
+        raise ValueError(
+            "DAC voltage must be greater than 0.0 and less than 5.0"
+        )
 
     mmc.setProperty(device_name, prop_name, str(value))
     time.sleep(20 / 1000)
@@ -229,7 +243,9 @@ def define_meadowlark_state(mmc, device_property: tuple):
     mmc.waitForDevice(device_name)
 
 
-def define_config_state(mmc, group: str, config: str, device_properties: list, values: list):
+def define_config_state(
+    mmc, group: str, config: str, device_properties: list, values: list
+):
     """
     Define config state by specifying the values for all device properties in this config
 
@@ -274,4 +290,4 @@ def set_lc_state(mmc, group: str, config: str):
     """
 
     mmc.setConfig(group, config)
-    time.sleep(20/1000)  # delay for LC settle time
\ No newline at end of file
+    time.sleep(20 / 1000)  # delay for LC settle time
diff --git a/recOrder/io/metadata_reader.py b/recOrder/io/metadata_reader.py
index a77230d7..65fce0b0 100644
--- a/recOrder/io/metadata_reader.py
+++ b/recOrder/io/metadata_reader.py
@@ -4,14 +4,20 @@
 
 
 def load_json(path):
-    with open(path, 'r') as f:
+    with open(path, "r") as f:
         data = json.load(f)
 
     return data
 
 
 def get_last_metadata_file(path):
-    last_metadata_file = natsorted([file for file in os.listdir(path) if file.startswith('calibration_metadata')])[-1]
+    last_metadata_file = natsorted(
+        [
+            file
+            for file in os.listdir(path)
+            if file.startswith("calibration_metadata")
+        ]
+    )[-1]
     return os.path.join(path, last_metadata_file)
 
 
@@ -30,38 +36,42 @@ def __init__(self, path: str):
         self.metadata_path = path
         self.json_metadata = load_json(self.metadata_path)
 
-        self.Timestamp = self.get_summary_calibration_attr('Timestamp')
-        self.recOrder_napari_verion = self.get_summary_calibration_attr('recOrder-napari version')
-        self.waveorder_version = self.get_summary_calibration_attr('waveorder version')
+        self.Timestamp = self.get_summary_calibration_attr("Timestamp")
+        self.recOrder_napari_verion = self.get_summary_calibration_attr(
+            "recOrder-napari version"
+        )
+        self.waveorder_version = self.get_summary_calibration_attr(
+            "waveorder version"
+        )
         self.Calibration_scheme = self.get_calibration_scheme()
         self.Swing = self.get_swing()
-        self.Wavelength = self.get_summary_calibration_attr('Wavelength (nm)')
+        self.Wavelength = self.get_summary_calibration_attr("Wavelength (nm)")
         self.Black_level = self.get_black_level()
         self.Extinction_ratio = self.get_extinction_ratio()
-        self.ROI = tuple(self.get_roi()) # JSON does not preserve tuples
+        self.ROI = tuple(self.get_roi())  # JSON does not preserve tuples
         self.Channel_names = self.get_channel_names()
-        self.LCA_retardance = self.get_lc_retardance('LCA')
-        self.LCB_retardance = self.get_lc_retardance('LCB')
-        self.LCA_voltage = self.get_lc_voltage('LCA')
-        self.LCB_voltage = self.get_lc_voltage('LCB')
+        self.LCA_retardance = self.get_lc_retardance("LCA")
+        self.LCB_retardance = self.get_lc_retardance("LCB")
+        self.LCA_voltage = self.get_lc_voltage("LCA")
+        self.LCB_voltage = self.get_lc_voltage("LCB")
         self.Swing_measured = self.get_swing_measured()
         self.Notes = self.get_notes()
 
     def get_summary_calibration_attr(self, attr):
         try:
-            val = self.json_metadata['Summary'][attr]
+            val = self.json_metadata["Summary"][attr]
         except KeyError:
             try:
-                val = self.json_metadata['Calibration'][attr]
+                val = self.json_metadata["Calibration"][attr]
             except KeyError:
                 val = None
         return val
 
     def get_cal_states(self):
-        if self.Calibration_scheme == '4-State':
-            states = ['ext', '0', '60', '120']
-        elif self.Calibration_scheme == '5-State':
-            states = ['ext', '0', '45', '90', '135']
+        if self.Calibration_scheme == "4-State":
+            states = ["ext", "0", "60", "120"]
+        elif self.Calibration_scheme == "5-State":
+            states = ["ext", "0", "45", "90", "135"]
         return states
 
     def get_lc_retardance(self, lc):
@@ -79,13 +89,28 @@ def get_lc_retardance(self, lc):
 
         val = None
         try:
-            val = [self.json_metadata['Calibration']['LC retardance'][f'{lc}_{state}'] for state in states]
+            val = [
+                self.json_metadata["Calibration"]["LC retardance"][
+                    f"{lc}_{state}"
+                ]
+                for state in states
+            ]
         except KeyError:
-            states[0] = 'Ext'
-            if lc == 'LCA':
-                val = [self.json_metadata['Summary'][f'[LCA_{state}, LCB_{state}]'][0] for state in states]
-            elif lc == 'LCB':
-                val = [self.json_metadata['Summary'][f'[LCA_{state}, LCB_{state}]'][1] for state in states]
+            states[0] = "Ext"
+            if lc == "LCA":
+                val = [
+                    self.json_metadata["Summary"][
+                        f"[LCA_{state}, LCB_{state}]"
+                    ][0]
+                    for state in states
+                ]
+            elif lc == "LCB":
+                val = [
+                    self.json_metadata["Summary"][
+                        f"[LCA_{state}, LCB_{state}]"
+                    ][1]
+                    for state in states
+                ]
 
         return val
 
@@ -103,68 +128,82 @@ def get_lc_voltage(self, lc):
         states = self.get_cal_states()
 
         val = None
-        if 'Calibration' in self.json_metadata:
-            lc_voltage = self.json_metadata['Calibration']['LC voltage']
+        if "Calibration" in self.json_metadata:
+            lc_voltage = self.json_metadata["Calibration"]["LC voltage"]
             if lc_voltage:
-                val = [self.json_metadata['Calibration']['LC voltage'][f'{lc}_{state}'] for state in states]
+                val = [
+                    self.json_metadata["Calibration"]["LC voltage"][
+                        f"{lc}_{state}"
+                    ]
+                    for state in states
+                ]
 
         return val
 
     def get_swing(self):
         try:
-            val = self.json_metadata['Calibration']['Swing (waves)']
+            val = self.json_metadata["Calibration"]["Swing (waves)"]
         except KeyError:
-            val = self.json_metadata['Summary']['Swing (fraction)']
+            val = self.json_metadata["Summary"]["Swing (fraction)"]
         return val
 
     def get_swing_measured(self):
         states = self.get_cal_states()
         try:
-            val = [self.json_metadata['Calibration'][f'Swing_{state}'] for state in states[1:]]
+            val = [
+                self.json_metadata["Calibration"][f"Swing_{state}"]
+                for state in states[1:]
+            ]
         except KeyError:
-            val = [self.json_metadata['Summary'][f'Swing{state}'] for state in states[1:]]
+            val = [
+                self.json_metadata["Summary"][f"Swing{state}"]
+                for state in states[1:]
+            ]
 
         return val
 
     def get_calibration_scheme(self):
         try:
-            val = self.json_metadata['Calibration']['Calibration scheme']
+            val = self.json_metadata["Calibration"]["Calibration scheme"]
         except KeyError:
-            val = self.json_metadata['Summary']['Acquired Using']
+            val = self.json_metadata["Summary"]["Acquired Using"]
         return val
 
     def get_black_level(self):
         try:
-            val = self.json_metadata['Calibration']['Black level']
+            val = self.json_metadata["Calibration"]["Black level"]
         except KeyError:
-            val = self.json_metadata['Summary']['BlackLevel']
+            val = self.json_metadata["Summary"]["BlackLevel"]
         return val
 
     def get_extinction_ratio(self):
         try:
-            val = self.json_metadata['Calibration']['Extinction ratio']
+            val = self.json_metadata["Calibration"]["Extinction ratio"]
         except KeyError:
-            val = self.json_metadata['Summary']['Extinction Ratio']
+            val = self.json_metadata["Summary"]["Extinction Ratio"]
         return val
 
     def get_roi(self):
         try:
-            val = self.json_metadata['Calibration']['ROI (x, y, width, height)']
+            val = self.json_metadata["Calibration"][
+                "ROI (x, y, width, height)"
+            ]
         except KeyError:
-            val = self.json_metadata['Summary']['ROI Used (x, y, width, height)']
+            val = self.json_metadata["Summary"][
+                "ROI Used (x, y, width, height)"
+            ]
         return val
 
     def get_channel_names(self):
         try:
-            val = self.json_metadata['Calibration']['Channel names']
+            val = self.json_metadata["Calibration"]["Channel names"]
         except KeyError:
-            val = self.json_metadata['Summary']['ChNames']
+            val = self.json_metadata["Summary"]["ChNames"]
         return val
 
     def get_notes(self):
         try:
-            val = self.json_metadata['Notes']
+            val = self.json_metadata["Notes"]
         except KeyError:
             val = None
         return val
-
diff --git a/recOrder/io/utils.py b/recOrder/io/utils.py
index 7ab08c87..00eb91ca 100644
--- a/recOrder/io/utils.py
+++ b/recOrder/io/utils.py
@@ -282,7 +282,9 @@ def generic_hsv_overlay(
     return overlay_final[0] if mode == "2D" else overlay_final
 
 
-def ret_ori_overlay(retardance, orientation, ret_max = 10, mode="2D", cmap="JCh"):
+def ret_ori_overlay(
+    retardance, orientation, ret_max=10, mode="2D", cmap="JCh"
+):
     """
     This function will create an overlay of retardance and orientation with two different colormap options.
     HSV is the standard Hue, Saturation, Value colormap while JCh is a similar colormap but is perceptually uniform.
diff --git a/recOrder/io/zarr_converter.py b/recOrder/io/zarr_converter.py
index b030f42e..cae4c775 100644
--- a/recOrder/io/zarr_converter.py
+++ b/recOrder/io/zarr_converter.py
@@ -17,7 +17,14 @@ class ZarrConverter:
     for tiled acquisitions)
     """
 
-    def __init__(self, input_dir, output_dir, data_type=None, replace_position_names=False, format_hcs=False):
+    def __init__(
+        self,
+        input_dir,
+        output_dir,
+        data_type=None,
+        replace_position_names=False,
+        format_hcs=False,
+    ):
         """
 
         Parameters
@@ -32,26 +39,33 @@ def __init__(self, input_dir, output_dir, data_type=None, replace_position_names
         format_hcs: bool
         """
 
-        if not output_dir.endswith('.zarr'):
-            raise ValueError('Please specify .zarr at the end of your output')
+        if not output_dir.endswith(".zarr"):
+            raise ValueError("Please specify .zarr at the end of your output")
 
         # Init File IO Properties
-        self.version = 'recOrder converter version=0.5'
+        self.version = "recOrder converter version=0.5"
         self.data_directory = input_dir
         self.save_directory = os.path.dirname(output_dir)
         # self.files = glob.glob(os.path.join(self.data_directory, '*.tif'))
         self.meta_file = None
 
-        print('Initializing Data...')
-        self.reader = WaveorderReader(self.data_directory, data_type, extract_data=False)
+        print("Initializing Data...")
+        self.reader = WaveorderReader(
+            self.data_directory, data_type, extract_data=False
+        )
         self.data_type = self.reader.data_type
-        print('Finished initializing data')
+        print("Finished initializing data")
 
-        self.summary_metadata = self.reader.mm_meta['Summary'] if self.reader.mm_meta else None
+        self.summary_metadata = (
+            self.reader.mm_meta["Summary"] if self.reader.mm_meta else None
+        )
         self.save_name = os.path.basename(output_dir)
-        if self.data_type != 'upti':
-            self.mfile_name = os.path.join(self.save_directory, f'{self.save_name.strip(".zarr")}_ImagePlaneMetadata.txt')
-            self.meta_file = open(self.mfile_name, 'a')
+        if self.data_type != "upti":
+            self.mfile_name = os.path.join(
+                self.save_directory,
+                f'{self.save_name.strip(".zarr")}_ImagePlaneMetadata.txt',
+            )
+            self.meta_file = open(self.mfile_name, "a")
 
         self.replace_position_names = replace_position_names
         self.format_hcs = format_hcs
@@ -78,19 +92,28 @@ def __init__(self, input_dir, output_dir, data_type=None, replace_position_names
         self.dim = (self.p, self.t, self.c, self.z, self.y, self.x)
         self.focus_z = self.z // 2
         self.prefix_list = []
-        print(f'Found Dataset {self.save_name} w/ dimensions (P, T, C, Z, Y, X): {self.dim}')
+        print(
+            f"Found Dataset {self.save_name} w/ dimensions (P, T, C, Z, Y, X): {self.dim}"
+        )
 
         # Generate coordinate set
         self._gen_coordset()
 
         # Initialize Metadata Dictionary
         self.metadata = dict()
-        self.metadata['recOrder_Converter_Version'] = self.version
-        self.metadata['Summary'] = self.summary_metadata
+        self.metadata["recOrder_Converter_Version"] = self.version
+        self.metadata["Summary"] = self.summary_metadata
 
         # initialize metadata if HCS desired, init writer
-        self.hcs_meta = self._generate_hcs_metadata() if self.format_hcs else None
-        self.writer = WaveorderWriter(self.save_directory, hcs=self.format_hcs, hcs_meta=self.hcs_meta, verbose=False)
+        self.hcs_meta = (
+            self._generate_hcs_metadata() if self.format_hcs else None
+        )
+        self.writer = WaveorderWriter(
+            self.save_directory,
+            hcs=self.format_hcs,
+            hcs_meta=self.hcs_meta,
+            verbose=False,
+        )
         self.writer.create_zarr_root(self.save_name)
 
     def _gen_coordset(self):
@@ -105,28 +128,38 @@ def _gen_coordset(self):
         """
 
         # if acquisition information is not present, make an arbitrary dimension order
-        if not self.summary_metadata or 'AxisOrder' not in self.summary_metadata.keys():
+        if (
+            not self.summary_metadata
+            or "AxisOrder" not in self.summary_metadata.keys()
+        ):
 
             self.p_dim = 0
             self.t_dim = 1
             self.c_dim = 2
             self.z_dim = 3
 
-            self.dim_order = ['position', 'time', 'channel', 'z']
+            self.dim_order = ["position", "time", "channel", "z"]
 
             # Assume data was collected slice first
-            dims = [self.reader.slices, self.reader.channels, self.reader.frames, self.reader.get_num_positions()]
+            dims = [
+                self.reader.slices,
+                self.reader.channels,
+                self.reader.frames,
+                self.reader.get_num_positions(),
+            ]
 
         # get the order in which the data was collected to minimize i/o calls
         else:
             # 4 possible dimensions: p, c, t, z
             n_dim = 4
-            hashmap = {'position': self.p,
-                       'time': self.t,
-                       'channel': self.c,
-                       'z': self.z}
+            hashmap = {
+                "position": self.p,
+                "time": self.t,
+                "channel": self.c,
+                "z": self.z,
+            }
 
-            self.dim_order = copy.copy(self.summary_metadata['AxisOrder'])
+            self.dim_order = copy.copy(self.summary_metadata["AxisOrder"])
 
             dims = []
             for i in range(n_dim):
@@ -137,14 +170,19 @@ def _gen_coordset(self):
 
             # Reverse the dimension order and gather dimension indices
             self.dim_order.reverse()
-            self.p_dim = self.dim_order.index('position')
-            self.t_dim = self.dim_order.index('time')
-            self.c_dim = self.dim_order.index('channel')
-            self.z_dim = self.dim_order.index('z')
+            self.p_dim = self.dim_order.index("position")
+            self.t_dim = self.dim_order.index("time")
+            self.c_dim = self.dim_order.index("channel")
+            self.z_dim = self.dim_order.index("z")
 
         # create array of coordinate tuples with innermost dimension being the first dim acquired
-        self.coords = [(dim3, dim2, dim1, dim0) for dim3 in range(dims[3]) for dim2 in range(dims[2])
-                       for dim1 in range(dims[1]) for dim0 in range(dims[0])]
+        self.coords = [
+            (dim3, dim2, dim1, dim0)
+            for dim3 in range(dims[3])
+            for dim2 in range(dims[2])
+            for dim1 in range(dims[1])
+            for dim0 in range(dims[0])
+        ]
 
     def _get_position_coords(self):
 
@@ -152,16 +190,16 @@ def _get_position_coords(self):
         col_max = 0
         coords_list = []
 
-        #TODO: read rows, cols directly from XY corods
-        #TODO: account for non MM2gamma meta?
+        # TODO: read rows, cols directly from XY corods
+        # TODO: account for non MM2gamma meta?
         for idx, pos in enumerate(self.reader.stage_positions):
-            coords_list.append(pos['XYStage'])
-            row = pos['GridRow']
-            col = pos['GridCol']
+            coords_list.append(pos["XYStage"])
+            row = pos["GridRow"]
+            col = pos["GridCol"]
             row_max = row if row > row_max else row_max
             col_max = col if col > col_max else col_max
 
-        return coords_list, row_max+1, col_max+1
+        return coords_list, row_max + 1, col_max + 1
 
     def _generate_hcs_metadata(self):
 
@@ -170,20 +208,31 @@ def _generate_hcs_metadata(self):
         position_grid = create_grid_from_coordinates(position_list, rows, cols)
 
         # Build metadata based off of position grid
-        hcs_meta = {'plate': {
-            'acquisitions': [{'id': 1,
-                              'maximumfieldcount': 1,
-                              'name': 'Dataset',
-                              'starttime': 0}],
-            'columns': [{'name': f'Col_{i}'} for i in range(cols)],
-
-            'field_count': 1,
-            'name': 'name',
-            'rows': [{'name': f'Row_{i}'} for i in range(rows)],
-            'version': '0.1',
-            'wells': [{'path': f'Row_{i}/Col_{j}'} for i in range(rows) for j in range(cols)]},
-
-            'well': [{'images': [{'path': f'Pos_{pos:03d}'}]} for pos in position_grid.flatten()]
+        hcs_meta = {
+            "plate": {
+                "acquisitions": [
+                    {
+                        "id": 1,
+                        "maximumfieldcount": 1,
+                        "name": "Dataset",
+                        "starttime": 0,
+                    }
+                ],
+                "columns": [{"name": f"Col_{i}"} for i in range(cols)],
+                "field_count": 1,
+                "name": "name",
+                "rows": [{"name": f"Row_{i}"} for i in range(rows)],
+                "version": "0.1",
+                "wells": [
+                    {"path": f"Row_{i}/Col_{j}"}
+                    for i in range(rows)
+                    for j in range(cols)
+                ],
+            },
+            "well": [
+                {"images": [{"path": f"Pos_{pos:03d}"}]}
+                for pos in position_grid.flatten()
+            ],
         }
 
         return hcs_meta
@@ -206,7 +255,7 @@ def _generate_plane_metadata(self, tiff_file, page):
         """
 
         for tag in tiff_file.pages[page].tags.values():
-            if tag.name == 'MicroManagerMetadata':
+            if tag.name == "MicroManagerMetadata":
                 return tag.value
             else:
                 continue
@@ -227,10 +276,12 @@ def _perform_image_check(self, tiff_image, coord):
 
         """
 
-        zarr_array = self.writer.sub_writer.current_pos_group['arr_0']
-        zarr_img = zarr_array[coord[self.dim_order.index('time')],
-                              coord[self.dim_order.index('channel')],
-                              coord[self.dim_order.index('z')]]
+        zarr_array = self.writer.sub_writer.current_pos_group["arr_0"]
+        zarr_img = zarr_array[
+            coord[self.dim_order.index("time")],
+            coord[self.dim_order.index("channel")],
+            coord[self.dim_order.index("z")],
+        ]
 
         return np.array_equal(zarr_img, tiff_image)
 
@@ -259,11 +310,11 @@ def _get_position_names(self):
         for p in range(self.p):
             if self.p > 1:
                 try:
-                    name = self.summary_metadata['StagePositions'][p]['Label']
+                    name = self.summary_metadata["StagePositions"][p]["Label"]
                 except KeyError:
-                    name = ''
+                    name = ""
             else:
-                name = ''
+                name = ""
             self.pos_names.append(name)
 
     def check_file_changed(self, last_file, current_file):
@@ -323,8 +374,8 @@ def get_channel_clims(self, pos):
         for chan in range(self.c):
             img = self.get_image_array(pos, t=0, c=chan, z=self.focus_z)
             clip = 0.01
-            low = np.percentile(img, clip*100)
-            high = np.percentile(img, (1-clip)*100)
+            low = np.percentile(img, clip * 100)
+            high = np.percentile(img, (1 - clip) * 100)
             clims.append((low, high))
 
         return clims
@@ -342,24 +393,27 @@ def init_zarr_structure(self):
 
         """
 
-
         chan_names = self._get_channel_names()
         self._get_position_names()
         for pos in range(self.p):
 
             clims = self.get_channel_clims(pos)
             name = self.pos_names[pos] if self.replace_position_names else None
-            self.writer.init_array(pos,
-                                   data_shape=(self.t if self.t != 0 else 1,
-                                               self.c if self.c != 0 else 1,
-                                               self.z if self.z != 0 else 1,
-                                               self.y,
-                                               self.x),
-                                   chunk_size=(1, 1, 1, self.y, self.x),
-                                   chan_names=chan_names,
-                                   clims=clims,
-                                   dtype=self.dtype,
-                                   position_name=name)
+            self.writer.init_array(
+                pos,
+                data_shape=(
+                    self.t if self.t != 0 else 1,
+                    self.c if self.c != 0 else 1,
+                    self.z if self.z != 0 else 1,
+                    self.y,
+                    self.x,
+                ),
+                chunk_size=(1, 1, 1, self.y, self.x),
+                chan_names=chan_names,
+                clims=clims,
+                dtype=self.dtype,
+                position_name=name,
+            )
 
     def run_conversion(self):
         """
@@ -372,25 +426,27 @@ def run_conversion(self):
         """
 
         # Run setup
-        print('Running Conversion...')
-        print('Setting up zarr')
+        print("Running Conversion...")
+        print("Setting up zarr")
         # self._gather_index_maps()
         self.init_zarr_structure()
         last_file = None
 
-        #Format bar for CLI display
-        bar_format = 'Status: |{bar}|{n_fmt}/{total_fmt} (Time Remaining: {remaining}), {rate_fmt}{postfix}]'
+        # Format bar for CLI display
+        bar_format = "Status: |{bar}|{n_fmt}/{total_fmt} (Time Remaining: {remaining}), {rate_fmt}{postfix}]"
 
         # Run through every coordinate and convert image + grab image metadata, statistics
         # loop is done in order in which the images were acquired
-        print('Converting Images...')
+        print("Converting Images...")
         for coord in tqdm(self.coords, bar_format=bar_format):
-            if self.data_type == 'ometiff':
+            if self.data_type == "ometiff":
                 # re-order coordinates into zarr format
-                coord_reorder = (coord[self.p_dim],
-                                 coord[self.t_dim],
-                                 coord[self.c_dim],
-                                 coord[self.z_dim])
+                coord_reorder = (
+                    coord[self.p_dim],
+                    coord[self.t_dim],
+                    coord[self.c_dim],
+                    coord[self.z_dim],
+                )
 
                 # Only load tiff file if it has changed from previous run
                 current_file = self.reader.reader.coord_map[coord_reorder][0]
@@ -403,29 +459,49 @@ def run_conversion(self):
 
                 meta = dict()
                 plane_meta = self._generate_plane_metadata(tf, page)
-                meta[f'{coord_reorder}'] = plane_meta
+                meta[f"{coord_reorder}"] = plane_meta
 
                 json.dump(meta, self.meta_file, indent=1)
-            elif self.data_type == 'pycromanager':
+            elif self.data_type == "pycromanager":
                 # write page metadata
-                plane_metadata = self.reader.reader.get_image_metadata(coord[self.p_dim],
-                                                                       coord[self.t_dim],
-                                                                       coord[self.c_dim],
-                                                                       coord[self.z_dim])
-
-                json.dump({f'FrameKey-{coord[self.p_dim]}-{coord[self.t_dim]}-'
-                           f'{coord[self.c_dim]}-{coord[self.z_dim]}': plane_metadata},
-                          self.meta_file, indent=1)
+                plane_metadata = self.reader.reader.get_image_metadata(
+                    coord[self.p_dim],
+                    coord[self.t_dim],
+                    coord[self.c_dim],
+                    coord[self.z_dim],
+                )
+
+                json.dump(
+                    {
+                        f"FrameKey-{coord[self.p_dim]}-{coord[self.t_dim]}-"
+                        f"{coord[self.c_dim]}-{coord[self.z_dim]}": plane_metadata
+                    },
+                    self.meta_file,
+                    indent=1,
+                )
 
             # get the memory mapped image
-            img_raw = self.get_image_array(coord[self.p_dim], coord[self.t_dim], coord[self.c_dim], coord[self.z_dim])
+            img_raw = self.get_image_array(
+                coord[self.p_dim],
+                coord[self.t_dim],
+                coord[self.c_dim],
+                coord[self.z_dim],
+            )
 
             # Write the data
-            self.writer.write(img_raw, coord[self.p_dim], coord[self.t_dim], coord[self.c_dim], coord[self.z_dim])
+            self.writer.write(
+                img_raw,
+                coord[self.p_dim],
+                coord[self.t_dim],
+                coord[self.c_dim],
+                coord[self.z_dim],
+            )
 
             # Perform image check
             if not self._perform_image_check(img_raw, coord):
-                raise ValueError('Converted zarr image does not match the raw data. Conversion Failed')
+                raise ValueError(
+                    "Converted zarr image does not match the raw data. Conversion Failed"
+                )
 
         # Put summary metadata into zarr store and cleanup
         self.writer.store.attrs.update(self.metadata)
diff --git a/recOrder/pipelines/base.py b/recOrder/pipelines/base.py
index 2c4b6264..38d89d99 100644
--- a/recOrder/pipelines/base.py
+++ b/recOrder/pipelines/base.py
@@ -20,5 +20,7 @@ def reconstruct_birefringence_volume(self, stokes):
         pass
 
     @abstractmethod
-    def write_data(self, p, t, pt_data, stokes, birefringence, deconvolve2D, deconvolve3D):
-        pass
\ No newline at end of file
+    def write_data(
+        self, p, t, pt_data, stokes, birefringence, deconvolve2D, deconvolve3D
+    ):
+        pass
diff --git a/recOrder/pipelines/phase_from_bf_pipeline.py b/recOrder/pipelines/phase_from_bf_pipeline.py
index 19aa1b46..9124bb37 100644
--- a/recOrder/pipelines/phase_from_bf_pipeline.py
+++ b/recOrder/pipelines/phase_from_bf_pipeline.py
@@ -2,13 +2,24 @@
 from waveorder.io.reader import WaveorderReader
 from waveorder.io.writer import WaveorderWriter
 from recOrder.io.utils import MockEmitter
-from recOrder.compute.qlipp_compute import reconstruct_phase2D, reconstruct_phase3D, initialize_reconstructor
+from recOrder.compute.qlipp_compute import (
+    reconstruct_phase2D,
+    reconstruct_phase3D,
+    initialize_reconstructor,
+)
 import numpy as np
 from recOrder.pipelines.base import PipelineInterface
 
-class PhaseFromBF(PipelineInterface):
 
-    def __init__(self, config: ConfigReader, data: WaveorderReader, writer: WaveorderWriter, num_t: int, emitter=MockEmitter()):
+class PhaseFromBF(PipelineInterface):
+    def __init__(
+        self,
+        config: ConfigReader,
+        data: WaveorderReader,
+        writer: WaveorderWriter,
+        num_t: int,
+        emitter=MockEmitter(),
+    ):
 
         # Dataset Parameters
         self.config = config
@@ -22,37 +33,44 @@ def __init__(self, config: ConfigReader, data: WaveorderReader, writer: Waveorde
         self.t = num_t
         self.output_channels = self.config.output_channels
         self._check_output_channels(self.output_channels)
-        self.mode = '2D' if 'Phase2D' in self.output_channels else '3D'
+        self.mode = "2D" if "Phase2D" in self.output_channels else "3D"
         self.bf_chan_idx = self.config.brightfield_channel_index
 
         self.slices = self.data.slices
         self.focus_slice = None
 
-        if self.mode == '2D':
+        if self.mode == "2D":
             self.slices = 1
             self.focus_slice = self.config.focus_zidx
 
         # Set image dimensions / writer parameters
         self.img_dim = (self.data.height, self.data.width, self.data.slices)
-        self.data_shape = (self.t, len(self.output_channels), self.slices, self.img_dim[0], self.img_dim[1])
+        self.data_shape = (
+            self.t,
+            len(self.output_channels),
+            self.slices,
+            self.img_dim[0],
+            self.img_dim[1],
+        )
         self.chunk_size = (1, 1, 1, self.data_shape[-2], self.data_shape[-1])
 
         # Initialize Reconstructor
-        self.reconstructor = initialize_reconstructor(pipeline='PhaseFromBF',
-                                                      image_dim=(self.img_dim[0], self.img_dim[1]),
-                                                      wavelength_nm=self.config.wavelength,
-                                                      NA_obj=self.config.NA_objective,
-                                                      NA_illu=self.config.NA_condenser,
-                                                      n_obj_media=self.config.n_objective_media,
-                                                      mag=self.config.magnification,
-                                                      n_slices=self.data.slices,
-                                                      z_step_um=self.data.z_step_size,
-                                                      pad_z=self.config.pad_z,
-                                                      pixel_size_um=self.config.pixel_size,
-                                                      mode=self.mode,
-                                                      use_gpu=self.config.use_gpu,
-                                                      gpu_id=self.config.gpu_id)
-
+        self.reconstructor = initialize_reconstructor(
+            pipeline="PhaseFromBF",
+            image_dim=(self.img_dim[0], self.img_dim[1]),
+            wavelength_nm=self.config.wavelength,
+            NA_obj=self.config.NA_objective,
+            NA_illu=self.config.NA_condenser,
+            n_obj_media=self.config.n_objective_media,
+            mag=self.config.magnification,
+            n_slices=self.data.slices,
+            z_step_um=self.data.z_step_size,
+            pad_z=self.config.pad_z,
+            pixel_size_um=self.config.pixel_size,
+            mode=self.mode,
+            use_gpu=self.config.use_gpu,
+            gpu_id=self.config.gpu_id,
+        )
 
     def _check_output_channels(self, output_channels):
         """
@@ -69,12 +87,14 @@ def _check_output_channels(self, output_channels):
         """
 
         for channel in output_channels:
-            if 'Phase3D' in channel:
+            if "Phase3D" in channel:
                 continue
-            elif 'Phase2D' in channel:
+            elif "Phase2D" in channel:
                 continue
-            elif 'Phase3D' in channel and 'Phase2D' in channel:
-                raise KeyError('Simultaneous 2D and 3D phase reconstruction not supported')
+            elif "Phase3D" in channel and "Phase2D" in channel:
+                raise KeyError(
+                    "Simultaneous 2D and 3D phase reconstruction not supported"
+                )
             else:
                 continue
 
@@ -124,19 +144,33 @@ def deconvolve_volume(self, bf_data):
         phase2D = None
         phase3D = None
 
-        if 'Phase3D' in self.output_channels:
-            phase3D = reconstruct_phase3D(bf_data, self.reconstructor, method=self.config.phase_denoiser_3D,
-                                          reg_re=self.config.Tik_reg_ph_3D, rho=self.config.rho_3D,
-                                          lambda_re=self.config.TV_reg_ph_3D, itr=self.config.itr_3D)
-
-        if 'Phase2D' in self.output_channels:
-            phase2D = reconstruct_phase2D(bf_data, self.reconstructor, method=self.config.phase_denoiser_2D,
-                                          reg_p=self.config.Tik_reg_ph_2D, rho=self.config.rho_2D,
-                                          lambda_p=self.config.TV_reg_ph_2D, itr=self.config.itr_2D)
+        if "Phase3D" in self.output_channels:
+            phase3D = reconstruct_phase3D(
+                bf_data,
+                self.reconstructor,
+                method=self.config.phase_denoiser_3D,
+                reg_re=self.config.Tik_reg_ph_3D,
+                rho=self.config.rho_3D,
+                lambda_re=self.config.TV_reg_ph_3D,
+                itr=self.config.itr_3D,
+            )
+
+        if "Phase2D" in self.output_channels:
+            phase2D = reconstruct_phase2D(
+                bf_data,
+                self.reconstructor,
+                method=self.config.phase_denoiser_2D,
+                reg_p=self.config.Tik_reg_ph_2D,
+                rho=self.config.rho_2D,
+                lambda_p=self.config.TV_reg_ph_2D,
+                itr=self.config.itr_2D,
+            )
 
         return phase2D, phase3D
 
-    def write_data(self, p, t, pt_data, stokes, birefringence, phase2D, phase3D):
+    def write_data(
+        self, p, t, pt_data, stokes, birefringence, phase2D, phase3D
+    ):
         """
         This function will iteratively write the data into its proper position, time, channel, z index.
         Dimensions differ between data type to make compute easier with waveOrder backend.
@@ -150,19 +184,19 @@ def write_data(self, p, t, pt_data, stokes, birefringence, phase2D, phase3D):
         birefringence:      (nd-array) None or nd-array w/ dimensions (C, Z, Y, X)
         phase2D:            (nd-array) None or nd-array w/ dimensions (Y, X)
         phase3D:            (nd-array) None or nd-array w/ dimensions (Z, Y, X)
-    
+
         Returns
         -------
         Writes a zarr array to to given save directory.
 
         """
-        z = 0 if self.mode == '2D' else None
-        slice_ = self.focus_slice if self.mode == '2D' else slice(None)
+        z = 0 if self.mode == "2D" else None
+        slice_ = self.focus_slice if self.mode == "2D" else slice(None)
 
         for chan in range(len(self.output_channels)):
-            if 'Phase3D' in self.output_channels[chan]:
+            if "Phase3D" in self.output_channels[chan]:
                 self.writer.write(phase3D, p=p, t=t, c=chan, z=z)
-            elif 'Phase2D' in self.output_channels[chan]:
+            elif "Phase2D" in self.output_channels[chan]:
                 self.writer.write(phase2D, p=p, t=t, c=chan, z=z)
 
-            self.dimension_emitter.emit((p, t, chan))
\ No newline at end of file
+            self.dimension_emitter.emit((p, t, chan))
diff --git a/recOrder/pipelines/pipeline_manager.py b/recOrder/pipelines/pipeline_manager.py
index 4289f6e1..bd9ff77e 100644
--- a/recOrder/pipelines/pipeline_manager.py
+++ b/recOrder/pipelines/pipeline_manager.py
@@ -18,18 +18,25 @@ class PipelineManager:
 
     """
 
-    def __init__(self, config: ConfigReader, overwrite: bool = False, emitter=MockEmitter()):
+    def __init__(
+        self,
+        config: ConfigReader,
+        overwrite: bool = False,
+        emitter=MockEmitter(),
+    ):
         self._check_ram()
-        
+
         start = time.time()
-        print('Reading Data...')
+        print("Reading Data...")
         data = WaveorderReader(config.data_dir, extract_data=True)
         end = time.time()
-        print(f'Finished Reading Data ({(end - start) / 60 :0.1f} min)')
+        print(f"Finished Reading Data ({(end - start) / 60 :0.1f} min)")
 
         self.config = config
         self.data = data
-        self.use_hcs = True if isinstance(self.data.reader, ZarrReader) else False
+        self.use_hcs = (
+            True if isinstance(self.data.reader, ZarrReader) else False
+        )
 
         self._gen_coord_set()
 
@@ -45,25 +52,47 @@ def __init__(self, config: ConfigReader, overwrite: bool = False, emitter=MockEm
         # Delete previous data if overwrite is true, helpful for making quick config changes since the writer
         # doesn't by default allow you to overwrite data
         if overwrite:
-            path = os.path.join(self.config.save_dir, self.config.data_save_name)
-            path = path+'.zarr' if not path.endswith('.zarr') else path
+            path = os.path.join(
+                self.config.save_dir, self.config.data_save_name
+            )
+            path = path + ".zarr" if not path.endswith(".zarr") else path
             if os.path.exists(path):
                 shutil.rmtree(path)
 
         # Writer Parameters
-        self.writer = WaveorderWriter(self.config.save_dir, hcs=self.use_hcs, hcs_meta=self.hcs_meta, verbose=False)
+        self.writer = WaveorderWriter(
+            self.config.save_dir,
+            hcs=self.use_hcs,
+            hcs_meta=self.hcs_meta,
+            verbose=False,
+        )
         self.writer.create_zarr_root(self.config.data_save_name)
 
         # Pipeline Initiation
-        if self.config.method == 'QLIPP':
-            self.pipeline = QLIPP(self.config, self.data, self.writer, self.config.mode, self.num_t, emitter=emitter)
-
-        elif self.config.method == 'PhaseFromBF':
-            self.pipeline = PhaseFromBF(self.config, self.data, self.writer, self.num_t, emitter=emitter)
+        if self.config.method == "QLIPP":
+            self.pipeline = QLIPP(
+                self.config,
+                self.data,
+                self.writer,
+                self.config.mode,
+                self.num_t,
+                emitter=emitter,
+            )
+
+        elif self.config.method == "PhaseFromBF":
+            self.pipeline = PhaseFromBF(
+                self.config,
+                self.data,
+                self.writer,
+                self.num_t,
+                emitter=emitter,
+            )
 
         else:
-            raise NotImplementedError(f'Method {self.config.method} is not currently implemented '
-                                      'please specify one of the following: QLIPP or PhaseFromBF')
+            raise NotImplementedError(
+                f"Method {self.config.method} is not currently implemented "
+                "please specify one of the following: QLIPP or PhaseFromBF"
+            )
 
     def _check_ram(self):
         """
@@ -99,10 +128,10 @@ def _update_hcs_meta_from_config(self, hcs_meta):
         for idx, p in enumerate(self.p_indices):
 
             # for every position, grab it from the original HCS metadata and place it into new list
-            well_meta = meta_new['well']
+            well_meta = meta_new["well"]
             well_meta_new[idx] = well_meta[p]
 
-            wells = meta_new['plate']['wells']
+            wells = meta_new["plate"]["wells"]
             wells_new[idx] = wells[p]
 
         # Filter out any blank entries
@@ -113,18 +142,18 @@ def _update_hcs_meta_from_config(self, hcs_meta):
         rows_new = []
         cols_new = []
         for well in wells_new:
-            split = well['path'].split('/')
-            if not {'name': split[0]} in rows_new:
-                rows_new.append({'name': split[0]})
+            split = well["path"].split("/")
+            if not {"name": split[0]} in rows_new:
+                rows_new.append({"name": split[0]})
 
-            if not {'name': split[1]} in cols_new:
-                cols_new.append({'name': split[1]})
+            if not {"name": split[1]} in cols_new:
+                cols_new.append({"name": split[1]})
 
         # Group all of the metadata together in one dictionary
-        meta_new['plate']['rows'] = rows_new
-        meta_new['plate']['columns'] = cols_new
-        meta_new['plate']['wells'] = wells_new
-        meta_new['well'] = well_meta_new
+        meta_new["plate"]["rows"] = rows_new
+        meta_new["plate"]["columns"] = cols_new
+        meta_new["plate"]["wells"] = wells_new
+        meta_new["well"] = well_meta_new
 
         return meta_new
 
@@ -146,7 +175,7 @@ def _gen_coord_set(self):
         # run through the different possible config specifications (ranges, single entries, 'all', etc.)
         cnt = 0
         for p_entry in self.config.positions:
-            if p_entry == 'all':
+            if p_entry == "all":
                 for p in range(self.data.get_num_positions()):
                     p_indices.add(p)
                     self.indices_map[p] = cnt
@@ -167,11 +196,13 @@ def _gen_coord_set(self):
                     self.indices_map[p] = cnt
                     cnt += 1
             else:
-                raise ValueError(f'Did not understand entry {p_entry} in config specified positions')
+                raise ValueError(
+                    f"Did not understand entry {p_entry} in config specified positions"
+                )
 
         # run through the different possible config specifications (ranges, single entries, 'all', etc.)
         for t_entry in self.config.timepoints:
-            if t_entry == 'all':
+            if t_entry == "all":
                 for t in range(self.data.frames):
                     t_indices.add(t)
                 break
@@ -181,10 +212,12 @@ def _gen_coord_set(self):
                 for t in t_entry:
                     t_indices.add(t)
             elif isinstance(t_entry, tuple):
-                for t in range(t_entry[0],t_entry[1]):
+                for t in range(t_entry[0], t_entry[1]):
                     t_indices.add(t)
             else:
-                raise ValueError(f'Did not understand entry {t_entry} in config specified positions')
+                raise ValueError(
+                    f"Did not understand entry {t_entry} in config specified positions"
+                )
 
         self.num_t = len(t_indices)
         self.num_p = len(p_indices)
@@ -201,48 +234,63 @@ def try_init_array(self, pt):
             # If not doing the full position, we still want semantic information on which positions
             # were reconstructed, so append the filename to the position (which would have otherwise been arbitrary)
             if not self.hcs_meta:
-                name = f'Pos_{pt[0]:03d}'
+                name = f"Pos_{pt[0]:03d}"
             else:
                 name = None
 
-            self.pipeline.writer.init_array(self.indices_map[pt[0]],
-                                            self.pipeline.data_shape,
-                                            self.pipeline.chunk_size,
-                                            self.pipeline.output_channels,
-                                            position_name=name)
+            self.pipeline.writer.init_array(
+                self.indices_map[pt[0]],
+                self.pipeline.data_shape,
+                self.pipeline.chunk_size,
+                self.pipeline.output_channels,
+                position_name=name,
+            )
 
         # assumes array exists already if there is an error thrown
         except:
             pass
 
-    #TODO: use arbol print statements
-    #TODO: Refactor Birefringence to Anisotropy
+    # TODO: use arbol print statements
+    # TODO: Refactor Birefringence to Anisotropy
     def run(self):
 
-        print(f'Beginning Reconstruction...')
+        print(f"Beginning Reconstruction...")
 
         for pt in sorted(self.pt_set):
             start_time = time.time()
 
             self.try_init_array(pt)
 
-            pt_data = self.data.get_zarr(pt[0])[pt[1]] # (C, Z, Y, X) virtual
+            pt_data = self.data.get_zarr(pt[0])[pt[1]]  # (C, Z, Y, X) virtual
 
             # will return pt_data if the pipeline does not compute stokes
             stokes = self.pipeline.reconstruct_stokes_volume(pt_data)
 
             # will return None if the pipeline doesn't support birefringence reconstruction
-            birefringence = self.pipeline.reconstruct_birefringence_volume(stokes)
+            birefringence = self.pipeline.reconstruct_birefringence_volume(
+                stokes
+            )
 
             # will return phase volumes
-            deconvolve2D, deconvolve3D = self.pipeline.deconvolve_volume(stokes)
-
-            self.pipeline.write_data(self.indices_map[pt[0]], pt[1], pt_data, stokes,
-                                     birefringence, deconvolve2D, deconvolve3D)
+            deconvolve2D, deconvolve3D = self.pipeline.deconvolve_volume(
+                stokes
+            )
+
+            self.pipeline.write_data(
+                self.indices_map[pt[0]],
+                pt[1],
+                pt_data,
+                stokes,
+                birefringence,
+                deconvolve2D,
+                deconvolve3D,
+            )
 
             end_time = time.time()
-            print(f'Finishing Reconstructing P = {pt[0]}, T = {pt[1]} ({(end_time-start_time)/60:0.2f}) min')
+            print(
+                f"Finishing Reconstructing P = {pt[0]}, T = {pt[1]} ({(end_time-start_time)/60:0.2f}) min"
+            )
 
             existing_meta = self.writer.store.attrs.asdict().copy()
-            existing_meta['Config'] = self.config.yaml_dict
-            self.writer.store.attrs.put(existing_meta)
\ No newline at end of file
+            existing_meta["Config"] = self.config.yaml_dict
+            self.writer.store.attrs.put(existing_meta)
diff --git a/recOrder/pipelines/qlipp_pipeline.py b/recOrder/pipelines/qlipp_pipeline.py
index 83f66eed..b3f5dd97 100644
--- a/recOrder/pipelines/qlipp_pipeline.py
+++ b/recOrder/pipelines/qlipp_pipeline.py
@@ -3,8 +3,13 @@
 from waveorder.io.writer import WaveorderWriter
 from recOrder.io import MetadataReader
 from recOrder.io.utils import load_bg, MockEmitter, rec_bkg_to_wo_bkg
-from recOrder.compute.qlipp_compute import reconstruct_qlipp_birefringence, reconstruct_qlipp_stokes, \
-    reconstruct_phase2D, reconstruct_phase3D, initialize_reconstructor
+from recOrder.compute.qlipp_compute import (
+    reconstruct_qlipp_birefringence,
+    reconstruct_qlipp_stokes,
+    reconstruct_phase2D,
+    reconstruct_phase3D,
+    initialize_reconstructor,
+)
 import numpy as np
 from recOrder.pipelines.base import PipelineInterface
 
@@ -15,7 +20,15 @@ class QLIPP(PipelineInterface):
     This class contains methods to reconstruct an entire QLIPP dataset
     """
 
-    def __init__(self, config: ConfigReader, data: WaveorderReader, writer: WaveorderWriter, mode: str, num_t: int, emitter=MockEmitter()):
+    def __init__(
+        self,
+        config: ConfigReader,
+        data: WaveorderReader,
+        writer: WaveorderWriter,
+        mode: str,
+        num_t: int,
+        emitter=MockEmitter(),
+    ):
         """
         Parameters
         ----------
@@ -41,11 +54,13 @@ def __init__(self, config: ConfigReader, data: WaveorderReader, writer: Waveorde
         self._check_output_channels(self.output_channels)
 
         if self.data.channels < 4:
-            raise ValueError(f'Number of Channels is {data.channels}, cannot be less than 4')
+            raise ValueError(
+                f"Number of Channels is {data.channels}, cannot be less than 4"
+            )
 
         self.slices = self.data.slices
         self.focus_slice = None
-        if self.mode == '2D':
+        if self.mode == "2D":
             self.slices = 1
             self.focus_slice = self.config.focus_zidx
 
@@ -53,68 +68,92 @@ def __init__(self, config: ConfigReader, data: WaveorderReader, writer: Waveorde
 
         # Metadata
         self.chan_names = self.data.channel_names
-        self.bg_path = self.config.background if self.config.background else None
+        self.bg_path = (
+            self.config.background if self.config.background else None
+        )
         if self.config.calibration_metadata:
             self.calib_meta = MetadataReader(self.config.calibration_metadata)
             self.calib_scheme = self.calib_meta.Calibration_scheme
-            self.bg_roi = self.calib_meta.ROI # TODO: remove for 1.0.0
+            self.bg_roi = self.calib_meta.ROI  # TODO: remove for 1.0.0
         else:
             self.calib_meta = None
-            self.calib_scheme = '4-State'
-            self.bg_roi = None # TODO: remove for 1.0.0
+            self.calib_scheme = "4-State"
+            self.bg_roi = None  # TODO: remove for 1.0.0
 
         # identify the image indicies corresponding to each polarization orientation
-        self.s0_idx, self.s1_idx, \
-        self.s2_idx, self.s3_idx, \
-        self.s4_idx, = self.parse_channel_idx(self.data.channel_names)
+        (
+            self.s0_idx,
+            self.s1_idx,
+            self.s2_idx,
+            self.s3_idx,
+            self.s4_idx,
+        ) = self.parse_channel_idx(self.data.channel_names)
 
         # Writer Parameters
-        self.data_shape = (self.t, len(self.output_channels), self.slices, self.img_dim[0], self.img_dim[1])
+        self.data_shape = (
+            self.t,
+            len(self.output_channels),
+            self.slices,
+            self.img_dim[0],
+            self.img_dim[1],
+        )
         self.chunk_size = (1, 1, 1, self.data_shape[-2], self.data_shape[-1])
 
-        wo_background_correction = rec_bkg_to_wo_bkg(self.config.background_correction)
+        wo_background_correction = rec_bkg_to_wo_bkg(
+            self.config.background_correction
+        )
 
         # Initialize Reconstructor
         if self.no_phase:
-            self.reconstructor = initialize_reconstructor(pipeline='birefringence',
-                                                          image_dim=(self.img_dim[0], self.img_dim[1]),
-                                                          wavelength_nm=self.config.wavelength,
-                                                          swing=self.calib_meta.Swing,
-                                                          calibration_scheme=self.calib_scheme,
-                                                          n_slices=self.data.slices,
-                                                          pad_z=self.config.pad_z,
-                                                          bg_correction=wo_background_correction,
-                                                          mode=self.mode,
-                                                          use_gpu=self.config.use_gpu,
-                                                          gpu_id=self.config.gpu_id)
+            self.reconstructor = initialize_reconstructor(
+                pipeline="birefringence",
+                image_dim=(self.img_dim[0], self.img_dim[1]),
+                wavelength_nm=self.config.wavelength,
+                swing=self.calib_meta.Swing,
+                calibration_scheme=self.calib_scheme,
+                n_slices=self.data.slices,
+                pad_z=self.config.pad_z,
+                bg_correction=wo_background_correction,
+                mode=self.mode,
+                use_gpu=self.config.use_gpu,
+                gpu_id=self.config.gpu_id,
+            )
 
         else:
-            self.reconstructor = initialize_reconstructor(pipeline='QLIPP',
-                                                          image_dim=(self.img_dim[0], self.img_dim[1]),
-                                                          wavelength_nm=self.config.wavelength,
-                                                          swing=self.calib_meta.Swing,
-                                                          calibration_scheme=self.calib_scheme,
-                                                          NA_obj=self.config.NA_objective,
-                                                          NA_illu=self.config.NA_condenser,
-                                                          n_obj_media=self.config.n_objective_media,
-                                                          mag=self.config.magnification,
-                                                          n_slices=self.data.slices,
-                                                          z_step_um=self.data.z_step_size,
-                                                          pad_z=self.config.pad_z,
-                                                          pixel_size_um=self.config.pixel_size,
-                                                          bg_correction=wo_background_correction,
-                                                          mode=self.mode,
-                                                          use_gpu=self.config.use_gpu,
-                                                          gpu_id=self.config.gpu_id)
+            self.reconstructor = initialize_reconstructor(
+                pipeline="QLIPP",
+                image_dim=(self.img_dim[0], self.img_dim[1]),
+                wavelength_nm=self.config.wavelength,
+                swing=self.calib_meta.Swing,
+                calibration_scheme=self.calib_scheme,
+                NA_obj=self.config.NA_objective,
+                NA_illu=self.config.NA_condenser,
+                n_obj_media=self.config.n_objective_media,
+                mag=self.config.magnification,
+                n_slices=self.data.slices,
+                z_step_um=self.data.z_step_size,
+                pad_z=self.config.pad_z,
+                pixel_size_um=self.config.pixel_size,
+                bg_correction=wo_background_correction,
+                mode=self.mode,
+                use_gpu=self.config.use_gpu,
+                gpu_id=self.config.gpu_id,
+            )
 
         # Prepare background corrections for waveorder
-        if self.config.background_correction in ['global', 'local_fit+']:
-            bg_data = load_bg(self.bg_path, self.img_dim[0], self.img_dim[1], self.bg_roi) # TODO: remove ROI for 1.0.0
+        if self.config.background_correction in ["global", "local_fit+"]:
+            bg_data = load_bg(
+                self.bg_path, self.img_dim[0], self.img_dim[1], self.bg_roi
+            )  # TODO: remove ROI for 1.0.0
             self.bg_stokes = self.reconstructor.Stokes_recon(bg_data)
-            self.bg_stokes = self.reconstructor.Stokes_transform(self.bg_stokes)
-        elif self.config.background_correction == 'local_fit':
+            self.bg_stokes = self.reconstructor.Stokes_transform(
+                self.bg_stokes
+            )
+        elif self.config.background_correction == "local_fit":
             self.bg_stokes = np.zeros((5, self.img_dim[0], self.img_dim[1]))
-            self.bg_stokes[0, ...] = 1  # Set background to "identity" Stokes parameters.
+            self.bg_stokes[
+                0, ...
+            ] = 1  # Set background to "identity" Stokes parameters.
         else:
             self.bg_stokes = None
 
@@ -122,14 +161,17 @@ def _check_output_channels(self, output_channels):
         self.no_birefringence = True
         self.no_phase = True
         for channel in output_channels:
-            if 'Retardance' in channel or 'Orientation' in channel or 'Brightfield' in channel:
+            if (
+                "Retardance" in channel
+                or "Orientation" in channel
+                or "Brightfield" in channel
+            ):
                 self.no_birefringence = False
-            if 'Phase3D' in channel or 'Phase2D' in channel:
+            if "Phase3D" in channel or "Phase2D" in channel:
                 self.no_phase = False
             else:
                 continue
 
-
     def reconstruct_stokes_volume(self, data):
         """
         This method reconstructs a stokes volume from raw data
@@ -146,16 +188,20 @@ def reconstruct_stokes_volume(self, data):
 
         """
 
-        if self.calib_scheme == '4-State':
-            LF_array = np.zeros([4, self.data.slices, self.data.height, self.data.width])
+        if self.calib_scheme == "4-State":
+            LF_array = np.zeros(
+                [4, self.data.slices, self.data.height, self.data.width]
+            )
 
             LF_array[0] = data[self.s0_idx]
             LF_array[1] = data[self.s1_idx]
             LF_array[2] = data[self.s2_idx]
             LF_array[3] = data[self.s3_idx]
 
-        elif self.calib_scheme == '5-State':
-            LF_array = np.zeros([5, self.data.slices, self.data.height, self.data.width])
+        elif self.calib_scheme == "5-State":
+            LF_array = np.zeros(
+                [5, self.data.slices, self.data.height, self.data.width]
+            )
             LF_array[0] = data[self.s0_idx]
             LF_array[1] = data[self.s1_idx]
             LF_array[2] = data[self.s2_idx]
@@ -163,9 +209,13 @@ def reconstruct_stokes_volume(self, data):
             LF_array[4] = data[self.s4_idx]
 
         else:
-            raise NotImplementedError(f"calibration scheme {self.calib_scheme} not implemented")
+            raise NotImplementedError(
+                f"calibration scheme {self.calib_scheme} not implemented"
+            )
 
-        stokes = reconstruct_qlipp_stokes(LF_array, self.reconstructor, self.bg_stokes)
+        stokes = reconstruct_qlipp_stokes(
+            LF_array, self.reconstructor, self.bg_stokes
+        )
 
         return stokes
 
@@ -189,15 +239,27 @@ def deconvolve_volume(self, stokes):
         phase2D = None
         phase3D = None
 
-        if 'Phase3D' in self.output_channels:
-            phase3D = reconstruct_phase3D(stokes[0], self.reconstructor, method=self.config.phase_denoiser_3D,
-                                          reg_re=self.config.Tik_reg_ph_3D, rho=self.config.rho_3D,
-                                          lambda_re=self.config.TV_reg_ph_3D, itr=self.config.itr_3D)
-
-        if 'Phase2D' in self.output_channels:
-            phase2D = reconstruct_phase2D(stokes[0], self.reconstructor, method=self.config.phase_denoiser_2D,
-                                          reg_p=self.config.Tik_reg_ph_2D, rho=self.config.rho_2D,
-                                          lambda_p=self.config.TV_reg_ph_2D, itr=self.config.itr_2D)
+        if "Phase3D" in self.output_channels:
+            phase3D = reconstruct_phase3D(
+                stokes[0],
+                self.reconstructor,
+                method=self.config.phase_denoiser_3D,
+                reg_re=self.config.Tik_reg_ph_3D,
+                rho=self.config.rho_3D,
+                lambda_re=self.config.TV_reg_ph_3D,
+                itr=self.config.itr_3D,
+            )
+
+        if "Phase2D" in self.output_channels:
+            phase2D = reconstruct_phase2D(
+                stokes[0],
+                self.reconstructor,
+                method=self.config.phase_denoiser_2D,
+                reg_p=self.config.Tik_reg_ph_2D,
+                rho=self.config.rho_2D,
+                lambda_p=self.config.TV_reg_ph_2D,
+                itr=self.config.itr_2D,
+            )
 
         return phase2D, phase3D
 
@@ -221,10 +283,18 @@ def reconstruct_birefringence_volume(self, stokes):
             return None
         else:
             return reconstruct_qlipp_birefringence(
-                                stokes[:, slice(None) if self.slices != 1 else self.focus_slice, :, :],
-                                self.reconstructor)
-
-    def write_data(self, p, t, pt_data, stokes, birefringence, phase2D, phase3D):
+                stokes[
+                    :,
+                    slice(None) if self.slices != 1 else self.focus_slice,
+                    :,
+                    :,
+                ],
+                self.reconstructor,
+            )
+
+    def write_data(
+        self, p, t, pt_data, stokes, birefringence, phase2D, phase3D
+    ):
         """
         This function will iteratively write the data into its proper position, time, channel, z index.
         Dimensions differ between data type to make compute easier with waveOrder backend.
@@ -245,30 +315,38 @@ def write_data(self, p, t, pt_data, stokes, birefringence, phase2D, phase3D):
 
         """
 
-        z = 0 if self.mode == '2D' else None
-        slice_ = self.focus_slice if self.mode == '2D' else slice(None)
+        z = 0 if self.mode == "2D" else None
+        slice_ = self.focus_slice if self.mode == "2D" else slice(None)
         # stokes = np.transpose(stokes, (-1, -4, -3, -2)) if len(stokes.shape) == 4 else stokes
-        
+
         for chan in range(len(self.output_channels)):
-            if 'Retardance' in self.output_channels[chan]:
+            if "Retardance" in self.output_channels[chan]:
                 ret = birefringence[0] / (2 * np.pi) * self.config.wavelength
                 self.writer.write(ret, p=p, t=t, c=chan, z=z)
-            elif 'Orientation' in self.output_channels[chan]:
+            elif "Orientation" in self.output_channels[chan]:
                 self.writer.write(birefringence[1], p=p, t=t, c=chan, z=z)
-            elif 'Brightfield' in self.output_channels[chan]:
+            elif "Brightfield" in self.output_channels[chan]:
                 self.writer.write(birefringence[2], p=p, t=t, c=chan, z=z)
-            elif 'Phase3D' in self.output_channels[chan]:
+            elif "Phase3D" in self.output_channels[chan]:
                 self.writer.write(phase3D, p=p, t=t, c=chan, z=z)
-            elif 'Phase2D' in self.output_channels[chan]:
+            elif "Phase2D" in self.output_channels[chan]:
                 self.writer.write(phase2D, p=p, t=t, c=chan, z=z)
-            elif 'S0' in self.output_channels[chan]:
-                self.writer.write(stokes[0, slice_, :, :], p=p, t=t, c=chan, z=z)
-            elif 'S1' in self.output_channels[chan]:
-                self.writer.write(stokes[1, slice_, :, :], p=p, t=t, c=chan, z=z)
-            elif 'S2' in self.output_channels[chan]:
-                self.writer.write(stokes[2, slice_, :, :], p=p, t=t, c=chan, z=z)
-            elif 'S3' in self.output_channels[chan]:
-                self.writer.write(stokes[3, slice_, :, :], p=p, t=t, c=chan, z=z)
+            elif "S0" in self.output_channels[chan]:
+                self.writer.write(
+                    stokes[0, slice_, :, :], p=p, t=t, c=chan, z=z
+                )
+            elif "S1" in self.output_channels[chan]:
+                self.writer.write(
+                    stokes[1, slice_, :, :], p=p, t=t, c=chan, z=z
+                )
+            elif "S2" in self.output_channels[chan]:
+                self.writer.write(
+                    stokes[2, slice_, :, :], p=p, t=t, c=chan, z=z
+                )
+            elif "S3" in self.output_channels[chan]:
+                self.writer.write(
+                    stokes[3, slice_, :, :], p=p, t=t, c=chan, z=z
+                )
 
             self.dimension_emitter.emit((p, t, chan))
 
@@ -292,26 +370,27 @@ def parse_channel_idx(self, channel_list):
         s2_idx = None
         s3_idx = None
         s4_idx = None
-        if 'PolScope_Plugin_Version' in self.calib_meta.json_metadata['Summary']:
+        if (
+            "PolScope_Plugin_Version"
+            in self.calib_meta.json_metadata["Summary"]
+        ):
             open_pol = True
         else:
             open_pol = False
 
         for channel in range(len(channel_list)):
-            if 'State0' in channel_list[channel]:
+            if "State0" in channel_list[channel]:
                 s0_idx = channel
-            elif 'State1' in channel_list[channel]:
+            elif "State1" in channel_list[channel]:
                 s1_idx = channel
-            elif 'State2' in channel_list[channel]:
+            elif "State2" in channel_list[channel]:
                 s2_idx = channel
-            elif 'State3' in channel_list[channel]:
+            elif "State3" in channel_list[channel]:
                 s3_idx = channel
-            elif 'State4' in channel_list[channel]:
+            elif "State4" in channel_list[channel]:
                 s4_idx = channel
 
         if open_pol:
             s1_idx, s2_idx, s3_idx, s4_idx = s4_idx, s3_idx, s1_idx, s2_idx
 
         return s0_idx, s1_idx, s2_idx, s3_idx, s4_idx
-
-
diff --git a/recOrder/plugin/__init__.py b/recOrder/plugin/__init__.py
index ce49ae06..bd7e37d3 100644
--- a/recOrder/plugin/__init__.py
+++ b/recOrder/plugin/__init__.py
@@ -1,2 +1,2 @@
 # data viewers that depend on napari
-name = "plugin"
\ No newline at end of file
+name = "plugin"
diff --git a/recOrder/plugin/qtdesigner/mplwidget.py b/recOrder/plugin/qtdesigner/mplwidget.py
index fbfd01b5..dbe70f6f 100644
--- a/recOrder/plugin/qtdesigner/mplwidget.py
+++ b/recOrder/plugin/qtdesigner/mplwidget.py
@@ -1,11 +1,12 @@
 # Imports
 from qtpy import QtWidgets
 import matplotlib
-matplotlib.use('QT5Agg')
+
+matplotlib.use("QT5Agg")
 from matplotlib.figure import Figure
 from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as Canvas
 
-matplotlib.use('QT5Agg')
+matplotlib.use("QT5Agg")
 
 # Matplotlib canvas class to create figure
 class MplCanvas(Canvas):
@@ -13,14 +14,19 @@ def __init__(self):
         self.fig = Figure()
         self.ax = self.fig.add_subplot(111)
         Canvas.__init__(self, self.fig)
-        Canvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
+        Canvas.setSizePolicy(
+            self,
+            QtWidgets.QSizePolicy.Expanding,
+            QtWidgets.QSizePolicy.Expanding,
+        )
         Canvas.updateGeometry(self)
 
+
 # Matplotlib widget
 class MplWidget(QtWidgets.QWidget):
     def __init__(self, parent=None):
-        QtWidgets.QWidget.__init__(self, parent)   # Inherit from QWidget
-        self.canvas = MplCanvas()                  # Create canvas object
-        self.vbl = QtWidgets.QVBoxLayout()         # Set box for plotting
+        QtWidgets.QWidget.__init__(self, parent)  # Inherit from QWidget
+        self.canvas = MplCanvas()  # Create canvas object
+        self.vbl = QtWidgets.QVBoxLayout()  # Set box for plotting
         self.vbl.addWidget(self.canvas)
         self.setLayout(self.vbl)
diff --git a/recOrder/plugin/widget/loading_widget.py b/recOrder/plugin/widget/loading_widget.py
index 2256b2fc..0ca69ac7 100644
--- a/recOrder/plugin/widget/loading_widget.py
+++ b/recOrder/plugin/widget/loading_widget.py
@@ -2,10 +2,12 @@
 from qtpy.QtGui import QPalette, QPainter, QBrush, QColor, QPen
 from qtpy.QtWidgets import QWidget, QPushButton
 
+
 class Overlay(QWidget):
     """
     ADAPTED FROM AYDIN https://github.com/royerlab/aydin/blob/master/aydin/gui/_qt/custom_widgets/overlay.py
     """
+
     def __init__(self, parent=None):
 
         # super().__init__(self, parent)
@@ -14,7 +16,6 @@ def __init__(self, parent=None):
         palette.setColor(palette.Background, Qt.transparent)
         self.setPalette(palette)
 
-
     def paintEvent(self, event):
         painter = QPainter()
         painter.begin(self)
@@ -58,4 +59,4 @@ def timerEvent(self, event):
 
     def hideEvent(self, event):
         self.killTimer(self.timer)
-        self.hide()
\ No newline at end of file
+        self.hide()
diff --git a/recOrder/plugin/widget/main_widget.py b/recOrder/plugin/widget/main_widget.py
index 627ff15b..9f681307 100644
--- a/recOrder/plugin/widget/main_widget.py
+++ b/recOrder/plugin/widget/main_widget.py
@@ -5,8 +5,16 @@
 from qtpy.QtGui import QPixmap, QColor
 from superqt import QDoubleRangeSlider, QRangeSlider
 from recOrder.calib import Calibration
-from recOrder.plugin.workers.calibration_workers import CalibrationWorker, BackgroundCaptureWorker, load_calibration
-from recOrder.plugin.workers.acquisition_workers import PolarizationAcquisitionWorker, ListeningWorker, BFAcquisitionWorker
+from recOrder.plugin.workers.calibration_workers import (
+    CalibrationWorker,
+    BackgroundCaptureWorker,
+    load_calibration,
+)
+from recOrder.plugin.workers.acquisition_workers import (
+    PolarizationAcquisitionWorker,
+    ListeningWorker,
+    BFAcquisitionWorker,
+)
 from recOrder.plugin.workers.reconstruction_workers import ReconstructionWorker
 from recOrder.plugin.qtdesigner import recOrder_ui
 from recOrder.io.core_functions import set_lc_state, snap_and_average
@@ -27,6 +35,7 @@
 import pathlib
 import textwrap
 
+
 class MainWidget(QWidget):
     """
     This is the main recOrder widget that houses all of the GUI components of recOrder.
@@ -52,10 +61,10 @@ def __init__(self, napari_viewer: Viewer):
         # Connect to MicroManager
         # I'm disconnecting and hiding this button for 0.2.0, TODO: reinstate for 1.0.0
         # In 1.0.0 we'll only have a single "Switch to Online/Offline" button in the "Calibration tab"
-        
+
         # self.ui.qbutton_mm_connect.clicked[bool].connect(self.connect_to_mm)
         self.ui.qbutton_mm_connect.hide()
-        
+
         # Calibration Tab
 
         # Remove QT creator calibration mode items
@@ -63,35 +72,49 @@ def __init__(self, napari_viewer: Viewer):
         self.ui.cb_calib_mode.removeItem(0)
 
         # Populate calibration modes from docstring
-        cal_docs = NumpyDocString(Calibration.QLIPP_Calibration.__init__.__doc__)
-        mode_docs = ' '.join(cal_docs['Parameters'][3].desc).split('* ')[1:]
+        cal_docs = NumpyDocString(
+            Calibration.QLIPP_Calibration.__init__.__doc__
+        )
+        mode_docs = " ".join(cal_docs["Parameters"][3].desc).split("* ")[1:]
         for i, mode_doc in enumerate(mode_docs):
-            mode_name, mode_tooltip = mode_doc.split(': ')
-            wrapped_tooltip = '\n'.join(textwrap.wrap(mode_tooltip, width=70))
+            mode_name, mode_tooltip = mode_doc.split(": ")
+            wrapped_tooltip = "\n".join(textwrap.wrap(mode_tooltip, width=70))
             self.ui.cb_calib_mode.addItem(mode_name)
-            self.ui.cb_calib_mode.setItemData(i, wrapped_tooltip, Qt.ToolTipRole)
+            self.ui.cb_calib_mode.setItemData(
+                i, wrapped_tooltip, Qt.ToolTipRole
+            )
 
         self.ui.qbutton_browse.clicked[bool].connect(self.browse_dir_path)
         self.ui.le_directory.editingFinished.connect(self.enter_dir_path)
         self.ui.le_directory.setText(str(Path.cwd()))
 
         self.ui.le_swing.editingFinished.connect(self.enter_swing)
-        self.ui.le_swing.setText('0.1')
+        self.ui.le_swing.setText("0.1")
         self.enter_swing()
 
         self.ui.le_wavelength.editingFinished.connect(self.enter_wavelength)
-        self.ui.le_wavelength.setText('532')
+        self.ui.le_wavelength.setText("532")
         self.enter_wavelength()
 
-        self.ui.cb_calib_scheme.currentIndexChanged[int].connect(self.enter_calib_scheme)
-        self.ui.cb_calib_mode.currentIndexChanged[int].connect(self.enter_calib_mode)
+        self.ui.cb_calib_scheme.currentIndexChanged[int].connect(
+            self.enter_calib_scheme
+        )
+        self.ui.cb_calib_mode.currentIndexChanged[int].connect(
+            self.enter_calib_mode
+        )
         self.ui.cb_lca.currentIndexChanged[int].connect(self.enter_dac_lca)
         self.ui.cb_lcb.currentIndexChanged[int].connect(self.enter_dac_lcb)
-        self.ui.chb_use_roi.stateChanged[int].connect(self.enter_use_cropped_roi)
+        self.ui.chb_use_roi.stateChanged[int].connect(
+            self.enter_use_cropped_roi
+        )
         self.ui.qbutton_calibrate.clicked[bool].connect(self.run_calibration)
         self.ui.qbutton_load_calib.clicked[bool].connect(self.load_calibration)
-        self.ui.qbutton_calc_extinction.clicked[bool].connect(self.calc_extinction)
-        self.ui.cb_config_group.currentIndexChanged[int].connect(self.enter_config_group)
+        self.ui.qbutton_calc_extinction.clicked[bool].connect(
+            self.calc_extinction
+        )
+        self.ui.cb_config_group.currentIndexChanged[int].connect(
+            self.enter_config_group
+        )
 
         # Capture Background
         self.ui.le_bg_folder.editingFinished.connect(self.enter_bg_folder_name)
@@ -99,110 +122,164 @@ def __init__(self, napari_viewer: Viewer):
         self.ui.qbutton_capture_bg.clicked[bool].connect(self.capture_bg)
 
         # Advanced
-        self.ui.cb_loglevel.currentIndexChanged[int].connect(self.enter_log_level)
+        self.ui.cb_loglevel.currentIndexChanged[int].connect(
+            self.enter_log_level
+        )
         self.ui.qbutton_push_note.clicked[bool].connect(self.push_note)
 
         # Acquisition Tab
         self.ui.qbutton_gui_mode.clicked[bool].connect(self.change_gui_mode)
-        self.ui.qbutton_browse_save_dir.clicked[bool].connect(self.browse_save_path)
+        self.ui.qbutton_browse_save_dir.clicked[bool].connect(
+            self.browse_save_path
+        )
         self.ui.le_save_dir.editingFinished.connect(self.enter_save_path)
         self.ui.le_save_dir.setText(str(Path.cwd()))
         self.ui.le_data_save_name.editingFinished.connect(self.enter_save_name)
-        self.ui.qbutton_listen.clicked[bool].connect(self.listen_and_reconstruct)
+        self.ui.qbutton_listen.clicked[bool].connect(
+            self.listen_and_reconstruct
+        )
 
         self.ui.le_zstart.editingFinished.connect(self.enter_zstart)
-        self.ui.le_zstart.setText('-1')
+        self.ui.le_zstart.setText("-1")
         self.enter_zstart()
 
         self.ui.le_zend.editingFinished.connect(self.enter_zend)
-        self.ui.le_zend.setText('1')
+        self.ui.le_zend.setText("1")
         self.enter_zend()
 
         self.ui.le_zstep.editingFinished.connect(self.enter_zstep)
-        self.ui.le_zstep.setText('0.25')
+        self.ui.le_zstep.setText("0.25")
         self.enter_zstep()
 
         self.ui.chb_use_gpu.stateChanged[int].connect(self.enter_use_gpu)
         self.ui.le_gpu_id.editingFinished.connect(self.enter_gpu_id)
 
-        self.ui.le_recon_wavelength.setText('532') # This parameter seems to be wired differently than others...investigate later
+        self.ui.le_recon_wavelength.setText(
+            "532"
+        )  # This parameter seems to be wired differently than others...investigate later
 
         self.ui.le_obj_na.editingFinished.connect(self.enter_obj_na)
-        self.ui.le_obj_na.setText('1.3')
+        self.ui.le_obj_na.setText("1.3")
         self.enter_obj_na()
 
         self.ui.le_cond_na.editingFinished.connect(self.enter_cond_na)
-        self.ui.le_cond_na.setText('0.5')
+        self.ui.le_cond_na.setText("0.5")
         self.enter_cond_na()
 
         self.ui.le_mag.editingFinished.connect(self.enter_mag)
-        self.ui.le_mag.setText('60')
+        self.ui.le_mag.setText("60")
         self.enter_mag()
 
         self.ui.le_ps.editingFinished.connect(self.enter_ps)
-        self.ui.le_ps.setText('6.9')
+        self.ui.le_ps.setText("6.9")
         self.enter_ps()
 
         self.ui.le_n_media.editingFinished.connect(self.enter_n_media)
-        self.ui.le_n_media.setText('1.3')
+        self.ui.le_n_media.setText("1.3")
         self.enter_n_media()
 
         self.ui.le_pad_z.editingFinished.connect(self.enter_pad_z)
-        self.ui.chb_pause_updates.stateChanged[int].connect(self.enter_pause_updates)
-        self.ui.cb_birefringence.currentIndexChanged[int].connect(self.enter_birefringence_dim)
+        self.ui.chb_pause_updates.stateChanged[int].connect(
+            self.enter_pause_updates
+        )
+        self.ui.cb_birefringence.currentIndexChanged[int].connect(
+            self.enter_birefringence_dim
+        )
         self.ui.cb_phase.currentIndexChanged[int].connect(self.enter_phase_dim)
 
         # Populate background correction GUI element
         for i in range(3):
             self.ui.cb_bg_method.removeItem(0)
-        bg_options = ['None','Measured','Estimated','Measured + Estimated']
-        tooltips = ['No background correction.',
-                    'Correct sample images with a background image acquired at an empty field of view, loaded from "Background Path".',
-                    'Estimate sample background by fitting a 2D surface to the sample images. Works well when structures are spatially distributed across the field of view and a clear background is unavailable.',
-                    'Apply "Measured" background correction and then "Estimated" background correction. Use to remove residual background after the sample retardance is corrected with measured background.']
+        bg_options = ["None", "Measured", "Estimated", "Measured + Estimated"]
+        tooltips = [
+            "No background correction.",
+            'Correct sample images with a background image acquired at an empty field of view, loaded from "Background Path".',
+            "Estimate sample background by fitting a 2D surface to the sample images. Works well when structures are spatially distributed across the field of view and a clear background is unavailable.",
+            'Apply "Measured" background correction and then "Estimated" background correction. Use to remove residual background after the sample retardance is corrected with measured background.',
+        ]
         for i, bg_option in enumerate(bg_options):
-            wrapped_tooltip = '\n'.join(textwrap.wrap(tooltips[i], width=70))
+            wrapped_tooltip = "\n".join(textwrap.wrap(tooltips[i], width=70))
             self.ui.cb_bg_method.addItem(bg_option)
-            self.ui.cb_bg_method.setItemData(i, wrapped_tooltip, Qt.ToolTipRole)
-        self.ui.cb_bg_method.currentIndexChanged[int].connect(self.enter_bg_correction)
+            self.ui.cb_bg_method.setItemData(
+                i, wrapped_tooltip, Qt.ToolTipRole
+            )
+        self.ui.cb_bg_method.currentIndexChanged[int].connect(
+            self.enter_bg_correction
+        )
 
         self.ui.le_bg_path.editingFinished.connect(self.enter_acq_bg_path)
-        self.ui.qbutton_browse_bg_path.clicked[bool].connect(self.browse_acq_bg_path)
-        self.ui.qbutton_acq_birefringence.clicked[bool].connect(self.acq_birefringence)
+        self.ui.qbutton_browse_bg_path.clicked[bool].connect(
+            self.browse_acq_bg_path
+        )
+        self.ui.qbutton_acq_birefringence.clicked[bool].connect(
+            self.acq_birefringence
+        )
         self.ui.qbutton_acq_phase.clicked[bool].connect(self.acq_phase)
-        self.ui.qbutton_acq_birefringence_phase.clicked[bool].connect(self.acq_birefringence_phase)
-        self.ui.cb_colormap.currentIndexChanged[int].connect(self.enter_colormap)
-        self.ui.chb_display_volume.stateChanged[int].connect(self.enter_use_full_volume)
-        self.ui.le_overlay_slice.editingFinished.connect(self.enter_display_slice)
-        self.ui.slider_value.sliderMoved[tuple].connect(self.handle_val_slider_move)
-        self.ui.slider_saturation.sliderMoved[tuple].connect(self.handle_sat_slider_move)
+        self.ui.qbutton_acq_birefringence_phase.clicked[bool].connect(
+            self.acq_birefringence_phase
+        )
+        self.ui.cb_colormap.currentIndexChanged[int].connect(
+            self.enter_colormap
+        )
+        self.ui.chb_display_volume.stateChanged[int].connect(
+            self.enter_use_full_volume
+        )
+        self.ui.le_overlay_slice.editingFinished.connect(
+            self.enter_display_slice
+        )
+        self.ui.slider_value.sliderMoved[tuple].connect(
+            self.handle_val_slider_move
+        )
+        self.ui.slider_saturation.sliderMoved[tuple].connect(
+            self.handle_sat_slider_move
+        )
 
         # Display Tab
-        self.viewer.layers.events.inserted.connect(self._add_layer_to_display_boxes)
-        self.viewer.layers.events.removed.connect(self._remove_layer_from_display_boxes)
-        self.ui.qbutton_create_overlay.clicked[bool].connect(self.create_overlay)
-        self.ui.cb_saturation.currentIndexChanged[int].connect(self.update_sat_scale)
-        self.ui.cb_value.currentIndexChanged[int].connect(self.update_value_scale)
+        self.viewer.layers.events.inserted.connect(
+            self._add_layer_to_display_boxes
+        )
+        self.viewer.layers.events.removed.connect(
+            self._remove_layer_from_display_boxes
+        )
+        self.ui.qbutton_create_overlay.clicked[bool].connect(
+            self.create_overlay
+        )
+        self.ui.cb_saturation.currentIndexChanged[int].connect(
+            self.update_sat_scale
+        )
+        self.ui.cb_value.currentIndexChanged[int].connect(
+            self.update_value_scale
+        )
         self.ui.le_sat_max.editingFinished.connect(self.enter_sat_max)
         self.ui.le_sat_min.editingFinished.connect(self.enter_sat_min)
         self.ui.le_val_max.editingFinished.connect(self.enter_val_max)
         self.ui.le_val_min.editingFinished.connect(self.enter_val_min)
 
         # Reconstruction
-        self.ui.qbutton_browse_data_dir.clicked[bool].connect(self.browse_data_dir)
-        self.ui.qbutton_browse_calib_meta.clicked[bool].connect(self.browse_calib_meta)
+        self.ui.qbutton_browse_data_dir.clicked[bool].connect(
+            self.browse_data_dir
+        )
+        self.ui.qbutton_browse_calib_meta.clicked[bool].connect(
+            self.browse_calib_meta
+        )
         self.ui.qbutton_load_config.clicked[bool].connect(self.load_config)
         self.ui.qbutton_save_config.clicked[bool].connect(self.save_config)
-        self.ui.qbutton_load_default_config.clicked[bool].connect(self.load_default_config)
+        self.ui.qbutton_load_default_config.clicked[bool].connect(
+            self.load_default_config
+        )
         self.ui.cb_method.currentIndexChanged[int].connect(self.enter_method)
         self.ui.cb_mode.currentIndexChanged[int].connect(self.enter_mode)
-        self.ui.le_calibration_metadata.editingFinished.connect(self.enter_calib_meta)
+        self.ui.le_calibration_metadata.editingFinished.connect(
+            self.enter_calib_meta
+        )
         self.ui.qbutton_reconstruct.clicked[bool].connect(self.reconstruct)
-        self.ui.cb_phase_denoiser.currentIndexChanged[int].connect(self.enter_phase_denoiser)
+        self.ui.cb_phase_denoiser.currentIndexChanged[int].connect(
+            self.enter_phase_denoiser
+        )
 
         # Logging
         log_box = QtLogger(self.ui.te_log)
-        log_box.setFormatter(logging.Formatter('%(levelname)s - %(message)s'))
+        log_box.setFormatter(logging.Formatter("%(levelname)s - %(message)s"))
         logging.getLogger().addHandler(log_box)
         logging.getLogger().setLevel(logging.INFO)
 
@@ -210,7 +287,7 @@ def __init__(self, napari_viewer: Viewer):
         self.mm_status_changed.connect(self.handle_mm_status_update)
 
         # Instantiate Attributes:
-        self.gui_mode = 'offline'
+        self.gui_mode = "offline"
         self.bridge = None
         self.mm = None
         self.mmc = None
@@ -221,21 +298,27 @@ def __init__(self, napari_viewer: Viewer):
         self.directory = str(Path.cwd())
 
         # Reconstruction / Calibration Parameter Defaults
-        self.calib_scheme = '4-State'
-        self.calib_mode = 'MM-Retardance'
-        self.interp_method = 'schnoor_fit'
-        self.config_group = 'Channel'
-        self.calib_channels = ['State0', 'State1', 'State2', 'State3', 'State4']
+        self.calib_scheme = "4-State"
+        self.calib_mode = "MM-Retardance"
+        self.interp_method = "schnoor_fit"
+        self.config_group = "Channel"
+        self.calib_channels = [
+            "State0",
+            "State1",
+            "State2",
+            "State3",
+            "State4",
+        ]
         self.last_calib_meta_file = None
         self.use_cropped_roi = False
-        self.bg_folder_name = 'BG'
+        self.bg_folder_name = "BG"
         self.n_avg = 5
         self.intensity_monitor = []
         self.save_directory = str(Path.cwd())
         self.save_name = None
-        self.bg_option = 'None'
-        self.birefringence_dim = '2D'
-        self.phase_dim = '2D'
+        self.bg_option = "None"
+        self.birefringence_dim = "2D"
+        self.phase_dim = "2D"
         self.gpu_id = 0
         self.use_gpu = False
         self.pad_z = 0
@@ -245,13 +328,13 @@ def __init__(self, napari_viewer: Viewer):
         self.lca_dac = None
         self.lcb_dac = None
         self.pause_updates = False
-        self.method = 'QLIPP'
-        self.mode = '3D'
+        self.method = "QLIPP"
+        self.mode = "3D"
         self.calib_path = str(Path.cwd())
         self.data_dir = str(Path.cwd())
         self.config_path = str(Path.cwd())
         self.save_config_path = str(Path.cwd())
-        self.colormap = 'HSV'
+        self.colormap = "HSV"
         self.use_full_volume = False
         self.display_slice = 0
         self.last_p = 0
@@ -264,26 +347,36 @@ def __init__(self, napari_viewer: Viewer):
         # Init Plot
         self.plot_item = self.ui.plot_widget.getPlotItem()
         self.plot_item.enableAutoRange()
-        self.plot_item.setLabel('left', 'Intensity')
+        self.plot_item.setLabel("left", "Intensity")
         self.ui.plot_widget.setBackground((32, 34, 40))
-        self.plot_sequence = 'Coarse'
+        self.plot_sequence = "Coarse"
 
         # Init thread worker
         self.worker = None
 
         # Display/Initialiaze GUI Images (plotting legends, recOrder logo)
-        recorder_dir = dirname(dirname(dirname(dirname(os.path.abspath(__file__)))))
-        jch_legend_path = os.path.join(recorder_dir, 'docs/images/JCh_legend.png')
-        hsv_legend_path = os.path.join(recorder_dir, 'docs/images/HSV_legend.png')
+        recorder_dir = dirname(
+            dirname(dirname(dirname(os.path.abspath(__file__))))
+        )
+        jch_legend_path = os.path.join(
+            recorder_dir, "docs/images/JCh_legend.png"
+        )
+        hsv_legend_path = os.path.join(
+            recorder_dir, "docs/images/HSV_legend.png"
+        )
         self.jch_pixmap = QPixmap(jch_legend_path)
         self.hsv_pixmap = QPixmap(hsv_legend_path)
         self.ui.label_orientation_image.setPixmap(self.hsv_pixmap)
-        logo_path = os.path.join(recorder_dir, 'docs/images/recOrder_plugin_logo.png')
+        logo_path = os.path.join(
+            recorder_dir, "docs/images/recOrder_plugin_logo.png"
+        )
         logo_pixmap = QPixmap(logo_path)
         self.ui.label_logo.setPixmap(logo_pixmap)
 
         # Get default config file
-        self.default_offline_config = os.path.join(recorder_dir, "recOrder/plugin/config_offline_default.yml")
+        self.default_offline_config = os.path.join(
+            recorder_dir, "recOrder/plugin/config_offline_default.yml"
+        )
 
         # Hide initial UI elements for later implementation or for later pop-up purposes
         self.ui.label_lca.hide()
@@ -308,7 +401,9 @@ def __init__(self, napari_viewer: Viewer):
         self.ui.chb_pause_updates.setHidden(True)
 
         # Hide temporarily unsupported "Overlay" functions
-        self.ui.tabWidget.setTabText(self.ui.tabWidget.indexOf(self.ui.Display), "Orientation Legend")
+        self.ui.tabWidget.setTabText(
+            self.ui.tabWidget.indexOf(self.ui.Display), "Orientation Legend"
+        )
         self.ui.label_orientation_legend.setHidden(True)
         self.ui.DisplayOptions.setHidden(True)
 
@@ -316,9 +411,11 @@ def __init__(self, napari_viewer: Viewer):
         self.ui.chb_use_roi.setHidden(True)
 
         # Set initial UI Properties
-        self.ui.le_gui_mode.setStyleSheet("border: 1px solid rgb(200,0,0); color: rgb(200,0,0);")
-        self.ui.te_log.setStyleSheet('background-color: rgb(32,34,40);')
-        self.ui.le_mm_status.setText('Not Connected')
+        self.ui.le_gui_mode.setStyleSheet(
+            "border: 1px solid rgb(200,0,0); color: rgb(200,0,0);"
+        )
+        self.ui.te_log.setStyleSheet("background-color: rgb(32,34,40);")
+        self.ui.le_mm_status.setText("Not Connected")
         self.ui.le_mm_status.setStyleSheet("border: 1px solid yellow;")
         self.ui.le_sat_min.setStyleSheet("background-color: rgba(0, 0, 0, 0);")
         self.ui.le_sat_max.setStyleSheet("background-color: rgba(0, 0, 0, 0);")
@@ -327,16 +424,22 @@ def __init__(self, napari_viewer: Viewer):
         self.setStyleSheet("QTabWidget::tab-bar {alignment: center;}")
         self.red_text = QColor(200, 0, 0, 255)
         self.original_tab_text = self.ui.tabWidget_3.tabBar().tabTextColor(0)
-        self.ui.tabWidget.parent().setObjectName('recOrder') # make sure the top says recOrder and not 'Form'
-        self.ui.tabWidget_2.setCurrentIndex(0) # set focus to "Plot" tab by default
-        self.ui.tabWidget_3.setCurrentIndex(0) # set focus to "General" tab by default
+        self.ui.tabWidget.parent().setObjectName(
+            "recOrder"
+        )  # make sure the top says recOrder and not 'Form'
+        self.ui.tabWidget_2.setCurrentIndex(
+            0
+        )  # set focus to "Plot" tab by default
+        self.ui.tabWidget_3.setCurrentIndex(
+            0
+        )  # set focus to "General" tab by default
 
         # No "Optional" text on offline mode's calibration metadata box
         self.ui.le_calibration_metadata.setPlaceholderText("")
 
         # disable wheel events for combo boxes
         for attr_name in dir(self.ui):
-            if 'cb_' in attr_name:
+            if "cb_" in attr_name:
                 attr = getattr(self.ui, attr_name)
                 attr.wheelEvent = lambda event: None
 
@@ -371,15 +474,19 @@ def _demote_slider_offline(self, ui_slider, range_):
 
         # Add back the sliders as range sliders with the same properties
         ui_slider = QSlider(getattr(self.ui, slider_parent))
-        sizePolicy.setHeightForWidth(ui_slider.sizePolicy().hasHeightForWidth())
+        sizePolicy.setHeightForWidth(
+            ui_slider.sizePolicy().hasHeightForWidth()
+        )
         ui_slider.setSizePolicy(sizePolicy)
         ui_slider.setOrientation(Qt.Horizontal)
         ui_slider.setObjectName(slider_name)
-        self.ui.gridLayout_26.addWidget(ui_slider,
-                                        slider_position[0],
-                                        slider_position[1],
-                                        slider_position[2],
-                                        slider_position[3])
+        self.ui.gridLayout_26.addWidget(
+            ui_slider,
+            slider_position[0],
+            slider_position[1],
+            slider_position[2],
+            slider_position[3],
+        )
         ui_slider.setRange(range_[0], range_[1])
 
     def _promote_slider_offline(self, ui_slider, range_):
@@ -411,15 +518,19 @@ def _promote_slider_offline(self, ui_slider, range_):
 
         # Add back the sliders as range sliders with the same properties
         ui_slider = QRangeSlider(getattr(self.ui, slider_parent))
-        sizePolicy.setHeightForWidth(ui_slider.sizePolicy().hasHeightForWidth())
+        sizePolicy.setHeightForWidth(
+            ui_slider.sizePolicy().hasHeightForWidth()
+        )
         ui_slider.setSizePolicy(sizePolicy)
         ui_slider.setOrientation(Qt.Horizontal)
         ui_slider.setObjectName(slider_name)
-        self.ui.gridLayout_26.addWidget(ui_slider,
-                                        slider_position[0],
-                                        slider_position[1],
-                                        slider_position[2],
-                                        slider_position[3])
+        self.ui.gridLayout_26.addWidget(
+            ui_slider,
+            slider_position[0],
+            slider_position[1],
+            slider_position[2],
+            slider_position[3],
+        )
         ui_slider.setRange(range_[0], range_[1])
 
     def _promote_slider_init(self):
@@ -437,39 +548,59 @@ def _promote_slider_init(self):
 
         # Get Information from regular sliders
         value_slider_idx = self.ui.gridLayout_17.indexOf(self.ui.slider_value)
-        value_slider_position = self.ui.gridLayout_17.getItemPosition(value_slider_idx)
+        value_slider_position = self.ui.gridLayout_17.getItemPosition(
+            value_slider_idx
+        )
         value_slider_parent = self.ui.slider_value.parent().objectName()
-        saturation_slider_idx = self.ui.gridLayout_17.indexOf(self.ui.slider_saturation)
-        saturation_slider_position = self.ui.gridLayout_17.getItemPosition(saturation_slider_idx)
-        saturation_slider_parent = self.ui.slider_saturation.parent().objectName()
+        saturation_slider_idx = self.ui.gridLayout_17.indexOf(
+            self.ui.slider_saturation
+        )
+        saturation_slider_position = self.ui.gridLayout_17.getItemPosition(
+            saturation_slider_idx
+        )
+        saturation_slider_parent = (
+            self.ui.slider_saturation.parent().objectName()
+        )
 
         # Remove regular sliders from the UI
         self.ui.gridLayout_17.removeWidget(self.ui.slider_value)
         self.ui.gridLayout_17.removeWidget(self.ui.slider_saturation)
 
         # Add back the sliders as range sliders with the same properties
-        self.ui.slider_saturation = QDoubleRangeSlider(getattr(self.ui, saturation_slider_parent))
-        sizePolicy.setHeightForWidth(self.ui.slider_saturation.sizePolicy().hasHeightForWidth())
+        self.ui.slider_saturation = QDoubleRangeSlider(
+            getattr(self.ui, saturation_slider_parent)
+        )
+        sizePolicy.setHeightForWidth(
+            self.ui.slider_saturation.sizePolicy().hasHeightForWidth()
+        )
         self.ui.slider_saturation.setSizePolicy(sizePolicy)
         self.ui.slider_saturation.setOrientation(Qt.Horizontal)
         self.ui.slider_saturation.setObjectName("slider_saturation")
-        self.ui.gridLayout_17.addWidget(self.ui.slider_saturation,
-                                        saturation_slider_position[0],
-                                        saturation_slider_position[1],
-                                        saturation_slider_position[2],
-                                        saturation_slider_position[3])
+        self.ui.gridLayout_17.addWidget(
+            self.ui.slider_saturation,
+            saturation_slider_position[0],
+            saturation_slider_position[1],
+            saturation_slider_position[2],
+            saturation_slider_position[3],
+        )
         self.ui.slider_saturation.setRange(0, 100)
 
-        self.ui.slider_value = QDoubleRangeSlider(getattr(self.ui, value_slider_parent))
-        sizePolicy.setHeightForWidth(self.ui.slider_value.sizePolicy().hasHeightForWidth())
+        self.ui.slider_value = QDoubleRangeSlider(
+            getattr(self.ui, value_slider_parent)
+        )
+        sizePolicy.setHeightForWidth(
+            self.ui.slider_value.sizePolicy().hasHeightForWidth()
+        )
         self.ui.slider_value.setSizePolicy(sizePolicy)
         self.ui.slider_value.setOrientation(Qt.Horizontal)
         self.ui.slider_value.setObjectName("slider_value")
-        self.ui.gridLayout_17.addWidget(self.ui.slider_value,
-                                        value_slider_position[0],
-                                        value_slider_position[1],
-                                        value_slider_position[2],
-                                        value_slider_position[3])
+        self.ui.gridLayout_17.addWidget(
+            self.ui.slider_value,
+            value_slider_position[0],
+            value_slider_position[1],
+            value_slider_position[2],
+            value_slider_position[3],
+        )
         self.ui.slider_value.setRange(0, 100)
 
     def _hide_acquisition_ui(self, val: bool):
@@ -490,10 +621,12 @@ def _hide_acquisition_ui(self, val: bool):
         # Calibration Tab
         self.ui.tabWidget.setTabEnabled(0, not val)
         if val:
-            self.ui.tabWidget.setStyleSheet("QTabBar::tab::disabled {width: 0; height: 0; margin: 0; padding: 0; border: none;} ")
+            self.ui.tabWidget.setStyleSheet(
+                "QTabBar::tab::disabled {width: 0; height: 0; margin: 0; padding: 0; border: none;} "
+            )
         else:
             self.ui.tabWidget.setStyleSheet("")
-            self.ui.le_mm_status.setText('Not Connected')
+            self.ui.le_mm_status.setText("Not Connected")
             self.ui.le_mm_status.setStyleSheet("border: 1px solid yellow;")
             self.mmc = None
             self.mm = None
@@ -528,7 +661,7 @@ def _hide_offline_ui(self, val: bool):
 
         # Processing Settings
         self.ui.groupBox_2.setHidden(val)
-        
+
     def _enable_buttons(self):
         """
         enables the buttons that were disabled during acquisition, calibration, or reconstruction
@@ -586,8 +719,10 @@ def _handle_error(self, exc):
 
         """
 
-        self.ui.tb_calib_assessment.setText(f'Error: {str(exc)}')
-        self.ui.tb_calib_assessment.setStyleSheet("border: 1px solid rgb(200,0,0);")
+        self.ui.tb_calib_assessment.setText(f"Error: {str(exc)}")
+        self.ui.tb_calib_assessment.setStyleSheet(
+            "border: 1px solid rgb(200,0,0);"
+        )
 
         # Reset ROI if it was cropped down during reconstruction
         if self.use_cropped_roi:
@@ -619,7 +754,9 @@ def _handle_load_finished(self):
         -------
 
         """
-        self.ui.tb_calib_assessment.setText('Previous calibration successfully loaded')
+        self.ui.tb_calib_assessment.setText(
+            "Previous calibration successfully loaded"
+        )
         self.ui.tb_calib_assessment.setStyleSheet("border: 1px solid green;")
         self.ui.progress_bar.setValue(100)
 
@@ -642,13 +779,22 @@ def _add_layer_to_display_boxes(self, val):
         """
 
         for layer in self.viewer.layers:
-            if 'Overlay' in layer.name:
+            if "Overlay" in layer.name:
                 continue
-            if layer.name not in [self.ui.cb_hue.itemText(i) for i in range(self.ui.cb_hue.count())]:
+            if layer.name not in [
+                self.ui.cb_hue.itemText(i)
+                for i in range(self.ui.cb_hue.count())
+            ]:
                 self.ui.cb_hue.addItem(layer.name)
-            if layer.name not in [self.ui.cb_saturation.itemText(i) for i in range(self.ui.cb_saturation.count())]:
+            if layer.name not in [
+                self.ui.cb_saturation.itemText(i)
+                for i in range(self.ui.cb_saturation.count())
+            ]:
                 self.ui.cb_saturation.addItem(layer.name)
-            if layer.name not in [self.ui.cb_value.itemText(i) for i in range(self.ui.cb_value.count())]:
+            if layer.name not in [
+                self.ui.cb_value.itemText(i)
+                for i in range(self.ui.cb_value.count())
+            ]:
                 self.ui.cb_value.addItem(layer.name)
 
     def _remove_layer_from_display_boxes(self, val):
@@ -687,15 +833,16 @@ def _set_tab_red(self, name, state):
         """
 
         # this map corresponds to the tab index in the TabWidget GUI element
-        name_map = {'General': 0,
-                    'Processing': 1}
+        name_map = {"General": 0, "Processing": 1}
 
         index = name_map[name]
 
         if state:
             self.ui.tabWidget_3.tabBar().setTabTextColor(index, self.red_text)
         else:
-            self.ui.tabWidget_3.tabBar().setTabTextColor(index, self.original_tab_text)
+            self.ui.tabWidget_3.tabBar().setTabTextColor(
+                index, self.original_tab_text
+            )
 
     def _check_line_edit(self, name):
         """
@@ -710,10 +857,10 @@ def _check_line_edit(self, name):
         -------
 
         """
-        le = getattr(self.ui, f'le_{name}')
+        le = getattr(self.ui, f"le_{name}")
         text = le.text()
 
-        if text == '':
+        if text == "":
             le.setStyleSheet("border: 1px solid rgb(200,0,0);")
             return False
         else:
@@ -736,59 +883,79 @@ def _check_requirements_for_acq(self, mode):
         """
 
         # Initialize all tabs in their default style (not red)
-        self._set_tab_red('General', False)
-        self._set_tab_red('Processing', False)
-        
+        self._set_tab_red("General", False)
+        self._set_tab_red("Processing", False)
+
         # initialize the variable to keep track of the success of the requirement check
         raise_error = False
 
         # define the fields required for the specific acquisition modes.  Matches LineEdit object names
-        phase_required = {'wavelength', 'mag', 'cond_na', 'obj_na', 'n_media',
-                          'phase_strength', 'ps', 'zstep'}
+        phase_required = {
+            "wavelength",
+            "mag",
+            "cond_na",
+            "obj_na",
+            "n_media",
+            "phase_strength",
+            "ps",
+            "zstep",
+        }
 
         # Initalize all fields in their default style (not red).
         for field in phase_required:
-            le = getattr(self.ui, f'le_{field}')
+            le = getattr(self.ui, f"le_{field}")
             le.setStyleSheet("")
-        
+
         # Check generally required fields
-        if mode == 'birefringence' or mode == 'phase':
-            success = self._check_line_edit('save_dir')
+        if mode == "birefringence" or mode == "phase":
+            success = self._check_line_edit("save_dir")
             if not success:
                 raise_error = True
-                self._set_tab_red('General', True)
+                self._set_tab_red("General", True)
 
             # check background path if 'Measured' or 'Measured + Estimated' is selected
-            if self.bg_option == 'local_fit+' or self.bg_option == 'global':
-                success = self._check_line_edit('bg_path')
+            if self.bg_option == "local_fit+" or self.bg_option == "global":
+                success = self._check_line_edit("bg_path")
                 if not success:
                     raise_error = True
-                    self._set_tab_red('General', True)
+                    self._set_tab_red("General", True)
 
         # Check phase specific fields
-        if mode == 'phase':
+        if mode == "phase":
 
             # add in extra requirement is user is acquiring PhaseFromBF
             if self.ui.chb_phase_from_bf.isChecked():
-                cont = self._check_line_edit('recon_wavelength')
-                tab = getattr(self.ui, f'le_recon_wavelength').parent().parent().objectName()
+                cont = self._check_line_edit("recon_wavelength")
+                tab = (
+                    getattr(self.ui, f"le_recon_wavelength")
+                    .parent()
+                    .parent()
+                    .objectName()
+                )
                 if not cont:
                     raise_error = True
                     self._set_tab_red(tab, True)
 
             for field in phase_required:
                 cont = self._check_line_edit(field)
-                tab = getattr(self.ui, f'le_{field}').parent().parent().objectName()
+                tab = (
+                    getattr(self.ui, f"le_{field}")
+                    .parent()
+                    .parent()
+                    .objectName()
+                )
                 if not cont:
                     raise_error = True
-                    if field != 'zstep':
+                    if field != "zstep":
                         self._set_tab_red(tab, True)
                 else:
                     continue
 
         # Alert the user to check and enter in the missing parameters
         if raise_error:
-            raise ValueError('Please enter in all of the parameters necessary for the acquisition')
+            raise ValueError(
+                "Please enter in all of the parameters necessary for the acquisition"
+            )
 
     def _check_requirements_for_reconstruction(self):
         """
@@ -802,8 +969,8 @@ def _check_requirements_for_reconstruction(self):
         """
 
         # Initalize all tab elements and reconstruct button to default state (not red)
-        self._set_tab_red('General', False)
-        self._set_tab_red('Processing', False)
+        self._set_tab_red("General", False)
+        self._set_tab_red("Processing", False)
         self.ui.qbutton_reconstruct.setStyleSheet("")
 
         # initalize the success variable of the requirement check
@@ -811,38 +978,73 @@ def _check_requirements_for_reconstruction(self):
 
         # gather the specified output channels (will determine which requirements are necessary to look at)
         output_channels = self.ui.le_output_channels.text()
-        output_channels = output_channels.split(',')
-        output_channels = [chan.replace(' ', '') for chan in output_channels]
+        output_channels = output_channels.split(",")
+        output_channels = [chan.replace(" ", "") for chan in output_channels]
 
         # intialize the reconstruction specific required fields
-        always_required = {'data_dir', 'save_dir', 'positions', 'timepoints', 'output_channels'}
-        birefringence_required = {'calibration_metadata', 'recon_wavelength'}
-        phase_required = {'recon_wavelength', 'mag', 'obj_na', 'cond_na', 'n_media',
-                          'phase_strength', 'ps'}
-        
+        always_required = {
+            "data_dir",
+            "save_dir",
+            "positions",
+            "timepoints",
+            "output_channels",
+        }
+        birefringence_required = {"calibration_metadata", "recon_wavelength"}
+        phase_required = {
+            "recon_wavelength",
+            "mag",
+            "obj_na",
+            "cond_na",
+            "n_media",
+            "phase_strength",
+            "ps",
+        }
+
         # intialize all UI elements in the default state
         for field in always_required:
-            le = getattr(self.ui, f'le_{field}')
+            le = getattr(self.ui, f"le_{field}")
             le.setStyleSheet("")
         for field in phase_required:
-            le = getattr(self.ui, f'le_{field}')
+            le = getattr(self.ui, f"le_{field}")
             le.setStyleSheet("")
         for field in always_required:
             cont = self._check_line_edit(field)
             if not cont:
                 success = False
-                if field == 'data_dir' or field == 'save_dir':
-                    self._set_tab_red('General', True)
-                if field == 'positions' or field == 'timepoints' or field == 'output_channels':
-                    self._set_tab_red('Processing', True)
+                if field == "data_dir" or field == "save_dir":
+                    self._set_tab_red("General", True)
+                if (
+                    field == "positions"
+                    or field == "timepoints"
+                    or field == "output_channels"
+                ):
+                    self._set_tab_red("Processing", True)
             else:
                 continue
 
-        possible_channels = ['Retardance', 'Orientation', 'BF', 'S0', 'S1', 'S2', 'S3', 'Phase2D', 'Phase3D']
-        bire_channels = ['Retardance', 'Orientation', 'BF', 'S0', 'S1', 'S2', 'S3']
+        possible_channels = [
+            "Retardance",
+            "Orientation",
+            "BF",
+            "S0",
+            "S1",
+            "S2",
+            "S3",
+            "Phase2D",
+            "Phase3D",
+        ]
+        bire_channels = [
+            "Retardance",
+            "Orientation",
+            "BF",
+            "S0",
+            "S1",
+            "S2",
+            "S3",
+        ]
         qlipp_channel_present = False
         bire_channel_present = False
-        if self.method == 'QLIPP':
+        if self.method == "QLIPP":
             for channel in output_channels:
                 if channel in possible_channels:
                     qlipp_channel_present = True
@@ -853,66 +1055,94 @@ def _check_requirements_for_reconstruction(self):
                 if bire_channel_present:
                     for field in birefringence_required:
                         cont = self._check_line_edit(field)
-                        tab = getattr(self.ui, f'le_{field}').parent().parent().objectName()
+                        tab = (
+                            getattr(self.ui, f"le_{field}")
+                            .parent()
+                            .parent()
+                            .objectName()
+                        )
                         if not cont:
-                            if field != 'calibration_metadata':
+                            if field != "calibration_metadata":
                                 self._set_tab_red(tab, True)
                             success = False
                         else:
                             # self._set_tab_red(tab, False)
                             continue
 
-                if 'Phase2D' in output_channels or 'Phase3D' in output_channels:
+                if (
+                    "Phase2D" in output_channels
+                    or "Phase3D" in output_channels
+                ):
                     for field in phase_required:
                         cont = self._check_line_edit(field)
-                        tab = getattr(self.ui, f'le_{field}').parent().parent().objectName()
+                        tab = (
+                            getattr(self.ui, f"le_{field}")
+                            .parent()
+                            .parent()
+                            .objectName()
+                        )
                         if not cont:
                             self._set_tab_red(tab, True)
                             success = False
                         else:
                             self._set_tab_red(tab, False)
                             continue
-                    if 'Phase2D' in output_channels and self.mode == '2D':
-                        cont = self._check_line_edit('focus_zidx')
+                    if "Phase2D" in output_channels and self.mode == "2D":
+                        cont = self._check_line_edit("focus_zidx")
                         if not cont:
-                            self._set_tab_red('Processing', True)
+                            self._set_tab_red("Processing", True)
                             success = False
             else:
-                self._set_tab_red('Processing', True)
-                self.ui.le_output_channels.setStyleSheet("border: 1px solid rgb(200,0,0);")
-                print('User did not specify any QLIPP Specific Channels')
+                self._set_tab_red("Processing", True)
+                self.ui.le_output_channels.setStyleSheet(
+                    "border: 1px solid rgb(200,0,0);"
+                )
+                print("User did not specify any QLIPP Specific Channels")
                 success = False
 
-        elif self.method == 'PhaseFromBF':
-            cont = self._check_line_edit('bf_chan')
-            tab = getattr(self.ui, f'le_bf_chan').parent().parent().objectName()
+        elif self.method == "PhaseFromBF":
+            cont = self._check_line_edit("bf_chan")
+            tab = (
+                getattr(self.ui, f"le_bf_chan").parent().parent().objectName()
+            )
             if not cont:
                 self._set_tab_red(tab, True)
                 success = False
 
-            if 'Phase2D' in output_channels or 'Phase3D' in output_channels:
+            if "Phase2D" in output_channels or "Phase3D" in output_channels:
                 for field in phase_required:
                     cont = self._check_line_edit(field)
-                    tab = getattr(self.ui, f'le_{field}').parent().parent().objectName()
+                    tab = (
+                        getattr(self.ui, f"le_{field}")
+                        .parent()
+                        .parent()
+                        .objectName()
+                    )
                     if not cont:
                         self._set_tab_red(tab, True)
                         success = False
                     else:
                         continue
-                if 'Phase2D' in output_channels and self.mode == '2D':
-                    cont = self._check_line_edit('focus_zidx')
+                if "Phase2D" in output_channels and self.mode == "2D":
+                    cont = self._check_line_edit("focus_zidx")
                     if not cont:
-                        self._set_tab_red('Processing', True)
+                        self._set_tab_red("Processing", True)
                         success = False
             else:
-                self._set_tab_red('Processing', True)
-                self.ui.le_output_channels.setStyleSheet("border: 1px solid rgb(200,0,0);")
-                print('User did not specify any PhaseFromBF Specific Channels (Phase2D, Phase3D)')
+                self._set_tab_red("Processing", True)
+                self.ui.le_output_channels.setStyleSheet(
+                    "border: 1px solid rgb(200,0,0);"
+                )
+                print(
+                    "User did not specify any PhaseFromBF Specific Channels (Phase2D, Phase3D)"
+                )
                 success = False
 
         else:
-            print('Error in parameter checks')
-            self.ui.qbutton_reconstruct.setStyleSheet("border: 1px solid rgb(200,0,0);")
+            print("Error in parameter checks")
+            self.ui.qbutton_reconstruct.setStyleSheet(
+                "border: 1px solid rgb(200,0,0);"
+            )
             success = False
 
         return success
@@ -937,119 +1167,167 @@ def _populate_config_from_app(self):
         self.save_directory = self.ui.le_save_dir.text()
         self.config_reader.method = self.method
         self.config_reader.mode = self.mode
-        self.config_reader.data_save_name = self.ui.le_data_save_name.text() if self.ui.le_data_save_name.text() != '' \
-                                            else pathlib.PurePath(self.data_dir).name
-        self.config_reader.calibration_metadata = self.ui.le_calibration_metadata.text()
+        self.config_reader.data_save_name = (
+            self.ui.le_data_save_name.text()
+            if self.ui.le_data_save_name.text() != ""
+            else pathlib.PurePath(self.data_dir).name
+        )
+        self.config_reader.calibration_metadata = (
+            self.ui.le_calibration_metadata.text()
+        )
         self.config_reader.background = self.ui.le_bg_path.text()
         self.config_reader.background_correction = self.bg_option
 
         # Assumes that positions/timepoints can either be 'all'; '[all]'; 1, 2, 3, N; (start, end)
         positions = self.ui.le_positions.text()
-        positions = positions.replace(' ', '')
-        if positions == 'all' or positions == "['all']" or positions == '[all]':
-            self.config_reader.positions = ['all']
-        elif positions.startswith('[') and positions.endswith(']'):
-            vals = positions[1:-1].split(',')
+        positions = positions.replace(" ", "")
+        if (
+            positions == "all"
+            or positions == "['all']"
+            or positions == "[all]"
+        ):
+            self.config_reader.positions = ["all"]
+        elif positions.startswith("[") and positions.endswith("]"):
+            vals = positions[1:-1].split(",")
             if len(vals) != 2:
-                self._set_tab_red('Processing', True)
-                self.ui.le_positions.setStyleSheet("border: 1px solid rgb(200,0,0);")
+                self._set_tab_red("Processing", True)
+                self.ui.le_positions.setStyleSheet(
+                    "border: 1px solid rgb(200,0,0);"
+                )
             else:
-                self._set_tab_red('Processing', False)
+                self._set_tab_red("Processing", False)
                 self.ui.le_positions.setStyleSheet("")
                 self.config_reader.positions = [(int(vals[0]), int(vals[1]))]
-        elif positions.startswith('(') and positions.endswith(')'):
+        elif positions.startswith("(") and positions.endswith(")"):
             self.config_reader.positions = [eval(positions)]
         else:
-            vals = positions.split(',')
+            vals = positions.split(",")
             vals = map(lambda x: int(x), vals)
             self.config_reader.positions = list(vals)
 
         timepoints = self.ui.le_timepoints.text()
-        timepoints = timepoints.replace(' ', '')
-        if timepoints == 'all' or timepoints == "['all']" or timepoints == '[all]':
-            self.config_reader.timepoints = ['all']
-        elif timepoints.startswith('[') and timepoints.endswith(']'):
-            vals = timepoints[1:-1].split(',')
+        timepoints = timepoints.replace(" ", "")
+        if (
+            timepoints == "all"
+            or timepoints == "['all']"
+            or timepoints == "[all]"
+        ):
+            self.config_reader.timepoints = ["all"]
+        elif timepoints.startswith("[") and timepoints.endswith("]"):
+            vals = timepoints[1:-1].split(",")
             if len(vals) != 2:
-                self._set_tab_red('Processing', True)
-                self.ui.le_timepoints.setStyleSheet("border: 1px solid rgb(200,0,0);")
+                self._set_tab_red("Processing", True)
+                self.ui.le_timepoints.setStyleSheet(
+                    "border: 1px solid rgb(200,0,0);"
+                )
             else:
-                self._set_tab_red('Processing', False)
+                self._set_tab_red("Processing", False)
                 self.ui.le_timepoints.setStyleSheet("")
                 self.config_reader.timepoints = [(int(vals[0]), int(vals[1]))]
-        elif timepoints.startswith('(') and timepoints.endswith(')'):
+        elif timepoints.startswith("(") and timepoints.endswith(")"):
             self.config_reader.timepoints = [eval(timepoints)]
         else:
-            vals = timepoints.split(',')
+            vals = timepoints.split(",")
             vals = map(lambda x: int(x), vals)
             self.config_reader.timepoints = list(vals)
 
         attrs = dir(self.ui)
-        skip = ['wavelength', 'pixel_size', 'magnification', 'NA_objective', 'NA_condenser', 'n_objective_media']
+        skip = [
+            "wavelength",
+            "pixel_size",
+            "magnification",
+            "NA_objective",
+            "NA_condenser",
+            "n_objective_media",
+        ]
         # TODO: Figure out how to catch errors in regularizer strength field
         for key, value in PROCESSING.items():
             if key not in skip:
-                if key == 'background_correction':
-                    bg_map = {0: 'None', 1: 'global', 2: 'local_fit', 3: 'local_fit+'}
-                    setattr(self.config_reader, key, bg_map[self.ui.cb_bg_method.currentIndex()])
-
-                elif key == 'output_channels':
+                if key == "background_correction":
+                    bg_map = {
+                        0: "None",
+                        1: "global",
+                        2: "local_fit",
+                        3: "local_fit+",
+                    }
+                    setattr(
+                        self.config_reader,
+                        key,
+                        bg_map[self.ui.cb_bg_method.currentIndex()],
+                    )
+
+                elif key == "output_channels":
 
                     # Reset style sheets
                     self.ui.le_output_channels.setStyleSheet("")
                     self.ui.cb_mode.setStyleSheet("")
-                    self._set_tab_red('Processing', False)
+                    self._set_tab_red("Processing", False)
 
                     # Make a list of the channels from the line edit string
                     field_text = self.ui.le_output_channels.text()
-                    channels = field_text.split(',')
-                    channels = [i.replace(' ', '') for i in channels]
+                    channels = field_text.split(",")
+                    channels = [i.replace(" ", "") for i in channels]
                     setattr(self.config_reader, key, channels)
 
-                    if 'Phase3D' in channels and 'Phase2D' in channels:
-                        self.ui.le_output_channels.setStyleSheet("border: 1px solid rgb(200,0,0);")
-                        self._set_tab_red('Processing', True)
+                    if "Phase3D" in channels and "Phase2D" in channels:
+                        self.ui.le_output_channels.setStyleSheet(
+                            "border: 1px solid rgb(200,0,0);"
+                        )
+                        self._set_tab_red("Processing", True)
+                        raise KeyError(
+                            f"Both Phase3D and Phase2D cannot be specified in output_channels.  Please compute "
+                            f"separately"
+                        )
+
+                    if "Phase3D" in channels and self.mode == "2D":
+                        self._set_tab_red("Processing", True)
+                        self.ui.le_output_channels.setStyleSheet(
+                            "border: 1px solid rgb(200,0,0);"
+                        )
+                        self.ui.cb_mode.setStyleSheet(
+                            "border: 1px solid rgb(200,0,0);"
+                        )
                         raise KeyError(
-                            f'Both Phase3D and Phase2D cannot be specified in output_channels.  Please compute '
-                            f'separately')
-
-                    if 'Phase3D' in channels and self.mode == '2D':
-                        self._set_tab_red('Processing', True)
-                        self.ui.le_output_channels.setStyleSheet("border: 1px solid rgb(200,0,0);")
-                        self.ui.cb_mode.setStyleSheet("border: 1px solid rgb(200,0,0);")
-                        raise KeyError(f'Specified mode is 2D and Phase3D was specified for reconstruction. '
-                                       'Only 2D reconstructions can be performed in 2D mode')
-
-                    if 'Phase2D' in channels and self.mode == '3D':
-                        self._set_tab_red('Processing', True)
-                        self.ui.le_output_channels.setStyleSheet("border: 1px solid rgb(200,0,0);")
-                        self.ui.cb_mode.setStyleSheet("border: 1px solid rgb(200,0,0);")
-                        raise KeyError(f'Specified mode is 3D and Phase2D was specified for reconstruction. '
-                                       'Only 3D reconstructions can be performed in 3D mode')
-
-                elif key == 'pad_z':
+                            f"Specified mode is 2D and Phase3D was specified for reconstruction. "
+                            "Only 2D reconstructions can be performed in 2D mode"
+                        )
+
+                    if "Phase2D" in channels and self.mode == "3D":
+                        self._set_tab_red("Processing", True)
+                        self.ui.le_output_channels.setStyleSheet(
+                            "border: 1px solid rgb(200,0,0);"
+                        )
+                        self.ui.cb_mode.setStyleSheet(
+                            "border: 1px solid rgb(200,0,0);"
+                        )
+                        raise KeyError(
+                            f"Specified mode is 3D and Phase2D was specified for reconstruction. "
+                            "Only 3D reconstructions can be performed in 3D mode"
+                        )
+
+                elif key == "pad_z":
                     val = self.ui.le_pad_z.text()
                     setattr(self.config_reader, key, int(val))
 
-                elif key == 'gpu_id':
+                elif key == "gpu_id":
                     val = self.ui.le_gpu_id.text()
                     setattr(self.config_reader, key, int(val))
 
-                elif key == 'use_gpu':
+                elif key == "use_gpu":
                     if self.ui.chb_use_gpu.isChecked():
                         setattr(self.config_reader, key, True)
                     else:
                         setattr(self.config_reader, key, False)
 
-                elif key == 'focus_zidx':
+                elif key == "focus_zidx":
                     val = self.ui.le_focus_zidx.text()
-                    if val == '':
+                    if val == "":
                         setattr(self.config_reader, key, None)
                     else:
                         setattr(self.config_reader, key, int(val))
 
                 else:
-                    attr_name = f'le_{key}'
+                    attr_name = f"le_{key}"
                     if attr_name in attrs:
                         le = getattr(self.ui, attr_name)
                         try:
@@ -1063,44 +1341,108 @@ def _populate_config_from_app(self):
                         continue
 
         # Manually enter in phase regularization
-        if self.mode == '3D':
+        if self.mode == "3D":
             if self.ui.cb_phase_denoiser.currentIndex() == 0:
-                setattr(self.config_reader, 'Tik_reg_ph_3D', float(self.ui.le_phase_strength.text()))
+                setattr(
+                    self.config_reader,
+                    "Tik_reg_ph_3D",
+                    float(self.ui.le_phase_strength.text()),
+                )
             else:
-                setattr(self.config_reader, 'TV_reg_ph_3D', float(self.ui.le_phase_strength.text()))
-                setattr(self.config_reader, 'rho_3D', float(self.ui.le_rho.text()))
-                setattr(self.config_reader, 'itr_3D', int(self.ui.le_itr.text()))
+                setattr(
+                    self.config_reader,
+                    "TV_reg_ph_3D",
+                    float(self.ui.le_phase_strength.text()),
+                )
+                setattr(
+                    self.config_reader, "rho_3D", float(self.ui.le_rho.text())
+                )
+                setattr(
+                    self.config_reader, "itr_3D", int(self.ui.le_itr.text())
+                )
 
         else:
             if self.ui.cb_phase_denoiser.currentIndex() == 0:
-                setattr(self.config_reader, 'Tik_reg_ph_2D', float(self.ui.le_phase_strength.text()))
+                setattr(
+                    self.config_reader,
+                    "Tik_reg_ph_2D",
+                    float(self.ui.le_phase_strength.text()),
+                )
             else:
-                setattr(self.config_reader, 'TV_reg_ph_2D', float(self.ui.le_phase_strength.text()))
-                setattr(self.config_reader, 'rho_2D', float(self.ui.le_rho.text()))
-                setattr(self.config_reader, 'itr_2D', int(self.ui.le_itr.text()))
-
-        if self.method == 'PhaseFromBF':
-            setattr(self.config_reader, 'wavelength', int(self.ui.le_recon_wavelength.text()))
-            setattr(self.config_reader, 'brightfield_channel_index',
-                      int(self.ui.le_bf_chan.text()))
+                setattr(
+                    self.config_reader,
+                    "TV_reg_ph_2D",
+                    float(self.ui.le_phase_strength.text()),
+                )
+                setattr(
+                    self.config_reader, "rho_2D", float(self.ui.le_rho.text())
+                )
+                setattr(
+                    self.config_reader, "itr_2D", int(self.ui.le_itr.text())
+                )
+
+        if self.method == "PhaseFromBF":
+            setattr(
+                self.config_reader,
+                "wavelength",
+                int(self.ui.le_recon_wavelength.text()),
+            )
+            setattr(
+                self.config_reader,
+                "brightfield_channel_index",
+                int(self.ui.le_bf_chan.text()),
+            )
 
             focus_zidx = self.ui.le_focus_zidx.text()
-            setattr(self.config_reader, 'focus_zidx', int(focus_zidx) if focus_zidx != '' else None)
+            setattr(
+                self.config_reader,
+                "focus_zidx",
+                int(focus_zidx) if focus_zidx != "" else None,
+            )
 
         else:
-            setattr(self.config_reader, 'wavelength', int(self.ui.le_recon_wavelength.text()))
+            setattr(
+                self.config_reader,
+                "wavelength",
+                int(self.ui.le_recon_wavelength.text()),
+            )
 
         # Parse name mismatch fields
-        setattr(self.config_reader, 'NA_objective', float(self.ui.le_obj_na.text()) if self.ui.le_obj_na.text() != ''
-                else None)
-        setattr(self.config_reader, 'NA_condenser', float(self.ui.le_cond_na.text()) if self.ui.le_cond_na.text() != ''
-                else None)
-        setattr(self.config_reader, 'pixel_size', float(self.ui.le_ps.text()) if self.ui.le_ps.text() != ''
-                else None)
-        setattr(self.config_reader, 'n_objective_media', float(self.ui.le_n_media.text())
-                if self.ui.le_n_media.text() != '' else None)
-        setattr(self.config_reader, 'magnification', float(self.ui.le_mag.text()) if self.ui.le_mag.text() != ''
-                else None)
+        setattr(
+            self.config_reader,
+            "NA_objective",
+            float(self.ui.le_obj_na.text())
+            if self.ui.le_obj_na.text() != ""
+            else None,
+        )
+        setattr(
+            self.config_reader,
+            "NA_condenser",
+            float(self.ui.le_cond_na.text())
+            if self.ui.le_cond_na.text() != ""
+            else None,
+        )
+        setattr(
+            self.config_reader,
+            "pixel_size",
+            float(self.ui.le_ps.text())
+            if self.ui.le_ps.text() != ""
+            else None,
+        )
+        setattr(
+            self.config_reader,
+            "n_objective_media",
+            float(self.ui.le_n_media.text())
+            if self.ui.le_n_media.text() != ""
+            else None,
+        )
+        setattr(
+            self.config_reader,
+            "magnification",
+            float(self.ui.le_mag.text())
+            if self.ui.le_mag.text() != ""
+            else None,
+        )
 
     def _populate_from_config(self):
         """
@@ -1118,47 +1460,53 @@ def _populate_from_config(self):
         self.save_directory = self.config_reader.save_dir
         self.ui.le_save_dir.setText(self.config_reader.save_dir)
         self.ui.le_data_save_name.setText(self.config_reader.data_save_name)
-        self.ui.le_calibration_metadata.setText(self.config_reader.calibration_metadata)
+        self.ui.le_calibration_metadata.setText(
+            self.config_reader.calibration_metadata
+        )
         self.ui.le_bg_path.setText(self.config_reader.background)
 
         self.mode = self.config_reader.mode
-        self.ui.cb_mode.setCurrentIndex(0) if self.mode == '3D' else self.ui.cb_mode.setCurrentIndex(1)
+        self.ui.cb_mode.setCurrentIndex(
+            0
+        ) if self.mode == "3D" else self.ui.cb_mode.setCurrentIndex(1)
         self.method = self.config_reader.method
-        if self.method == 'QLIPP':
+        if self.method == "QLIPP":
             self.ui.cb_method.setCurrentIndex(0)
-        elif self.method == 'PhaseFromBF':
+        elif self.method == "PhaseFromBF":
             self.ui.cb_method.setCurrentIndex(1)
         else:
-            print(f'Did not understand method from config: {self.method}')
+            print(f"Did not understand method from config: {self.method}")
             self.ui.cb_method.setStyleSheet("border: 1px solid rgb(200,0,0);")
 
         self.bg_option = self.config_reader.background_correction
-        if self.bg_option == 'None':
+        if self.bg_option == "None":
             self.ui.cb_bg_method.setCurrentIndex(0)
-        elif self.bg_option == 'global':
+        elif self.bg_option == "global":
             self.ui.cb_bg_method.setCurrentIndex(1)
-        elif self.bg_option == 'local_fit':
+        elif self.bg_option == "local_fit":
             self.ui.cb_bg_method.setCurrentIndex(2)
-        elif self.bg_option == 'local_fit+':
+        elif self.bg_option == "local_fit+":
             self.ui.cb_bg_method.setCurrentIndex(3)
         else:
-            print(f'Did not understand method from config: {self.method}')
+            print(f"Did not understand method from config: {self.method}")
             self.ui.cb_method.setStyleSheet("border: 1px solid rgb(200,0,0);")
 
         if isinstance(self.config_reader.positions, list):
             positions = self.config_reader.positions
-            text = ''
+            text = ""
             for idx, pos in enumerate(positions):
-                text += f'{pos}, ' if idx != len(positions) - 1 else f'{pos}'
+                text += f"{pos}, " if idx != len(positions) - 1 else f"{pos}"
                 self.ui.le_positions.setText(text)
         else:
             self.ui.le_positions.setText(str(self.config_reader.positions))
 
         if isinstance(self.config_reader.timepoints, list):
             timepoints = self.config_reader.timepoints
-            text = ''
+            text = ""
             for idx, time in enumerate(timepoints):
-                text += f'{time}, ' if idx != len(timepoints) - 1 else f'{time}'
+                text += (
+                    f"{time}, " if idx != len(timepoints) - 1 else f"{time}"
+                )
                 self.ui.le_timepoints.setText(text)
         else:
             self.ui.le_timepoints.setText(str(self.config_reader.timepoints))
@@ -1166,11 +1514,15 @@ def _populate_from_config(self):
         # Parse Processing name mismatch fields
         wavelengths = self.config_reader.wavelength
         if not isinstance(wavelengths, list):
-            self.ui.le_recon_wavelength.setText(str(int(self.config_reader.wavelength)))
+            self.ui.le_recon_wavelength.setText(
+                str(int(self.config_reader.wavelength))
+            )
         else:
-            text = ''
+            text = ""
             for idx, chan in enumerate(wavelengths):
-                text += f'{chan}, ' if idx != len(wavelengths) - 1 else f'{chan}'
+                text += (
+                    f"{chan}, " if idx != len(wavelengths) - 1 else f"{chan}"
+                )
             self.ui.le_recon_wavelength.setText(text)
 
         self.ui.le_obj_na.setText(str(self.config_reader.NA_objective))
@@ -1180,72 +1532,92 @@ def _populate_from_config(self):
         self.ui.le_mag.setText(str(self.config_reader.magnification))
 
         # Parse PhaseFromBF
-        if self.method == 'PhaseFromBF':
-            self.ui.le_bf_chan.setText(str(self.config_reader.brightfield_channel_index))
-        
+        if self.method == "PhaseFromBF":
+            self.ui.le_bf_chan.setText(
+                str(self.config_reader.brightfield_channel_index)
+            )
+
         # Parse processing automatically
         denoiser = None
         for key, val in PROCESSING.items():
-            if key == 'output_channels':
+            if key == "output_channels":
                 channels = self.config_reader.output_channels
-                text = ''
+                text = ""
                 for idx, chan in enumerate(channels):
-                    text += f'{chan}, ' if idx != len(channels)-1 else f'{chan}'
+                    text += (
+                        f"{chan}, " if idx != len(channels) - 1 else f"{chan}"
+                    )
 
                 self.ui.le_output_channels.setText(text)
 
-            elif key == 'focus_zidx':
+            elif key == "focus_zidx":
                 indices = self.config_reader.focus_zidx
                 if isinstance(indices, int):
                     self.ui.le_focus_zidx.setText(str(indices))
                 elif isinstance(indices, list):
-                    text = ''
+                    text = ""
                     for idx, val in enumerate(indices):
-                        text += f'{val}, ' if idx != len(indices) - 1 else f'{val}'
+                        text += (
+                            f"{val}, " if idx != len(indices) - 1 else f"{val}"
+                        )
 
                     self.ui.le_focus_zidx.setText(text)
 
-            elif key == 'use_gpu':
+            elif key == "use_gpu":
                 state = getattr(self.config_reader, key)
                 self.ui.chb_use_gpu.setChecked(state)
 
-            elif key == 'gpu_id':
+            elif key == "gpu_id":
                 val = str(int(getattr(self.config_reader, key)))
                 self.ui.le_gpu_id.setText(val)
 
-            elif key == 'pad_z':
+            elif key == "pad_z":
                 val = str(int(getattr(self.config_reader, key)))
                 self.ui.le_pad_z.setText(val)
 
-            elif key == 'focus_zidx':
+            elif key == "focus_zidx":
                 val = str(int(getattr(self.config_reader, key)))
                 self.ui.le_focus_zidx.setText(val)
 
-            elif hasattr(self.ui, f'le_{key}'):
-                le = getattr(self.ui, f'le_{key}')
-                le.setText(str(getattr(self.config_reader, key)) if not isinstance(getattr(self.config_reader, key),
-                                                                                   str) else getattr(self.config_reader,
-                                                                                                     key))
-            elif hasattr(self.ui, f'cb_{key}'):
-                cb = getattr(self.ui, f'cb_{key}')
+            elif hasattr(self.ui, f"le_{key}"):
+                le = getattr(self.ui, f"le_{key}")
+                le.setText(
+                    str(getattr(self.config_reader, key))
+                    if not isinstance(getattr(self.config_reader, key), str)
+                    else getattr(self.config_reader, key)
+                )
+            elif hasattr(self.ui, f"cb_{key}"):
+                cb = getattr(self.ui, f"cb_{key}")
                 items = [cb.itemText(i) for i in range(cb.count())]
                 cfg_attr = getattr(self.config_reader, key)
                 self.ui.cb_mode.setCurrentIndex(items.index(cfg_attr))
 
-            elif key == 'phase_denoiser_2D' or key == 'phase_denoiser_3D':
+            elif key == "phase_denoiser_2D" or key == "phase_denoiser_3D":
                 cb = self.ui.cb_phase_denoiser
-                cfg_attr = getattr(self.config_reader, f'phase_denoiser_{self.mode}')
+                cfg_attr = getattr(
+                    self.config_reader, f"phase_denoiser_{self.mode}"
+                )
                 denoiser = cfg_attr
-                cb.setCurrentIndex(0) if cfg_attr == 'Tikhonov' else cb.setCurrentIndex(1)
+                cb.setCurrentIndex(
+                    0
+                ) if cfg_attr == "Tikhonov" else cb.setCurrentIndex(1)
             else:
-                if denoiser == 'Tikhonov':
-                    strength = getattr(self.config_reader, f'Tik_reg_ph_{self.mode}')
+                if denoiser == "Tikhonov":
+                    strength = getattr(
+                        self.config_reader, f"Tik_reg_ph_{self.mode}"
+                    )
                     self.ui.le_phase_strength.setText(str(strength))
                 else:
-                    strength = getattr(self.config_reader, f'TV_reg_ph_{self.mode}')
+                    strength = getattr(
+                        self.config_reader, f"TV_reg_ph_{self.mode}"
+                    )
                     self.ui.le_phase_strength.setText(str(strength))
-                    self.ui.le_rho.setText(str(getattr(self.config_reader, f'rho_{self.mode}')))
-                    self.ui.le_itr.setText(str(getattr(self.config_reader, f'itr_{self.mode}')))
+                    self.ui.le_rho.setText(
+                        str(getattr(self.config_reader, f"rho_{self.mode}"))
+                    )
+                    self.ui.le_itr.setText(
+                        str(getattr(self.config_reader, f"itr_{self.mode}"))
+                    )
 
     @Slot(bool)
     def change_gui_mode(self):
@@ -1256,28 +1628,31 @@ def change_gui_mode(self):
         -------
 
         """
-        if self.gui_mode == 'offline':
-            self.ui.qbutton_gui_mode.setText('Switch to Offline')
-            self.ui.le_gui_mode.setText('Online')
-            self.ui.le_gui_mode.setStyleSheet("border: 1px solid green; color: green;")
+        if self.gui_mode == "offline":
+            self.ui.qbutton_gui_mode.setText("Switch to Offline")
+            self.ui.le_gui_mode.setText("Online")
+            self.ui.le_gui_mode.setStyleSheet(
+                "border: 1px solid green; color: green;"
+            )
             self._hide_offline_ui(True)
             self._hide_acquisition_ui(False)
-            self.gui_mode = 'online'
+            self.gui_mode = "online"
             self.connect_to_mm()
 
         else:
-            self.ui.qbutton_gui_mode.setText('Switch to Online')
-            self.ui.le_gui_mode.setText('Offline')
-            self.ui.le_gui_mode.setStyleSheet("border: 1px solid rgb(200,0,0); color: rgb(200,0,0);")
+            self.ui.qbutton_gui_mode.setText("Switch to Online")
+            self.ui.le_gui_mode.setText("Offline")
+            self.ui.le_gui_mode.setStyleSheet(
+                "border: 1px solid rgb(200,0,0); color: rgb(200,0,0);"
+            )
             self._hide_offline_ui(False)
             self._hide_acquisition_ui(True)
-            self.gui_mode = 'offline'
+            self.gui_mode = "offline"
             self.ui.cb_config_group.clear()
 
-            #Make sure button is still visible
+            # Make sure button is still visible
             self.ui.qbutton_mm_connect.setEnabled(True)
 
-
     @Slot(bool)
     def connect_to_mm(self):
         """
@@ -1289,8 +1664,8 @@ def connect_to_mm(self):
         -------
 
         """
-        RECOMMENDED_MM = '20220920'
-        ZMQ_TARGET_VERSION = '4.2.0'
+        RECOMMENDED_MM = "20220920"
+        ZMQ_TARGET_VERSION = "4.2.0"
         try:
             # Try to open Bridge. Requires micromanager to be open with server running.
             # This does not fail gracefully, so I'm wrapping it in its own try-except block.
@@ -1299,20 +1674,35 @@ def connect_to_mm(self):
                 self.mmc = self.bridge.get_core()
                 self.mm = self.bridge.get_studio()
             except:
-                print(("Could not establish pycromanager bridge.\n"
-                       "Is micromanager open?\n"
-                       "Is Tools > Options > Run server on port 4827 checked?\n"
-                       f"Are you using nightly build {RECOMMENDED_MM}?"))
+                print(
+                    (
+                        "Could not establish pycromanager bridge.\n"
+                        "Is micromanager open?\n"
+                        "Is Tools > Options > Run server on port 4827 checked?\n"
+                        f"Are you using nightly build {RECOMMENDED_MM}?"
+                    )
+                )
                 raise EnvironmentError
 
             # Warn the user if there is a MicroManager/ZMQ version mismatch
-            self.bridge._main_socket.send({"command": "connect", "debug": False})
+            self.bridge._main_socket.send(
+                {"command": "connect", "debug": False}
+            )
             reply_json = self.bridge._main_socket.receive(timeout=500)
-            zmq_mm_version = reply_json['version']
+            zmq_mm_version = reply_json["version"]
             if zmq_mm_version != ZMQ_TARGET_VERSION:
-                upgrade_str = 'upgrade' if version.parse(zmq_mm_version) < version.parse(ZMQ_TARGET_VERSION) else 'downgrade'
-                print(("WARNING: This version of Micromanager has not been tested with recOrder.\n"
-                      f"Please {upgrade_str} to MicroManager nightly build {RECOMMENDED_MM}."))
+                upgrade_str = (
+                    "upgrade"
+                    if version.parse(zmq_mm_version)
+                    < version.parse(ZMQ_TARGET_VERSION)
+                    else "downgrade"
+                )
+                print(
+                    (
+                        "WARNING: This version of Micromanager has not been tested with recOrder.\n"
+                        f"Please {upgrade_str} to MicroManager nightly build {RECOMMENDED_MM}."
+                    )
+                )
 
             # Find config group containing calibration channels
             # calib_channels is typically ['State0', 'State1', 'State2', ...]
@@ -1330,9 +1720,16 @@ def connect_to_mm(self):
                 config_list = []
                 for j in range(configs.size()):
                     config_list.append(configs.get(j))
-                if np.all([np.any([ch in config for config in config_list]) for ch in self.calib_channels]):
+                if np.all(
+                    [
+                        np.any([ch in config for config in config_list])
+                        for ch in self.calib_channels
+                    ]
+                ):
                     if not config_group_found:
-                        self.config_group = group  # set to first config group found
+                        self.config_group = (
+                            group  # set to first config group found
+                        )
                         config_group_found = True
                     self.ui.cb_config_group.addItem(group)
                 # not entirely sure what this part does, but I left it in
@@ -1341,28 +1738,32 @@ def connect_to_mm(self):
                     if ch not in self.calib_channels:
                         self.ui.cb_acq_channel.addItem(ch)
             if not config_group_found:
-                msg = f'No config group contains channels {self.calib_channels}. ' \
-                      'Please refer to the recOrder wiki on how to set up the config properly.'
-                self.ui.cb_config_group.setStyleSheet("border: 1px solid rgb(200,0,0);")
+                msg = (
+                    f"No config group contains channels {self.calib_channels}. "
+                    "Please refer to the recOrder wiki on how to set up the config properly."
+                )
+                self.ui.cb_config_group.setStyleSheet(
+                    "border: 1px solid rgb(200,0,0);"
+                )
                 raise KeyError(msg)
 
-
             # set startup LC control mode
             _devices = self.mmc.getLoadedDevices()
             loaded_devices = [_devices.get(i) for i in range(_devices.size())]
             if LC_DEVICE_NAME in loaded_devices:
-                config_desc = self.mmc.getConfigData('Channel','State0').getVerbose()
-                if 'String send to' in config_desc:
-                    self.calib_mode = 'MM-Retardance'
+                config_desc = self.mmc.getConfigData(
+                    "Channel", "State0"
+                ).getVerbose()
+                if "String send to" in config_desc:
+                    self.calib_mode = "MM-Retardance"
                     self.ui.cb_calib_mode.setCurrentIndex(0)
-                if 'Voltage (V)' in config_desc:
-                    self.calib_mode = 'MM-Voltage'
+                if "Voltage (V)" in config_desc:
+                    self.calib_mode = "MM-Voltage"
                     self.ui.cb_calib_mode.setCurrentIndex(1)
             else:
-                self.calib_mode = 'DAC'
+                self.calib_mode = "DAC"
                 self.ui.cb_calib_mode.setCurrentIndex(2)
 
-
             self.mm_status_changed.emit(True)
 
         except:
@@ -1371,20 +1772,22 @@ def connect_to_mm(self):
     @Slot(bool)
     def handle_mm_status_update(self, value):
         if value:
-            self.ui.le_mm_status.setText('Success!')
+            self.ui.le_mm_status.setText("Success!")
             self.ui.le_mm_status.setStyleSheet("background-color: green;")
-            #Disabling the button
+            # Disabling the button
             self.ui.qbutton_mm_connect.setEnabled(False)
         else:
-            #Make sure button is still visible if it fails
+            # Make sure button is still visible if it fails
             self.ui.qbutton_mm_connect.setEnabled(True)
-            self.ui.le_mm_status.setText('Failed.')
-            self.ui.le_mm_status.setStyleSheet("background-color: rgb(200,0,0);")
+            self.ui.le_mm_status.setText("Failed.")
+            self.ui.le_mm_status.setStyleSheet(
+                "background-color: rgb(200,0,0);"
+            )
 
     @Slot(tuple)
     def handle_progress_update(self, value):
         self.ui.progress_bar.setValue(value[0])
-        self.ui.label_progress.setText('Progress: ' + value[1])
+        self.ui.label_progress.setText("Progress: " + value[1])
 
     @Slot(str)
     def handle_extinction_update(self, value):
@@ -1409,12 +1812,17 @@ def handle_plot_update(self, value):
         self.intensity_monitor.append(value)
         self.ui.plot_widget.plot(self.intensity_monitor)
 
-        if self.plot_sequence[0] == 'Coarse':
+        if self.plot_sequence[0] == "Coarse":
             self.plot_item.autoRange()
         else:
-            self.plot_item.setRange(xRange=(self.plot_sequence[1], len(self.intensity_monitor)),
-                                    yRange=(0, np.max(self.intensity_monitor[self.plot_sequence[1]:])),
-                                    padding=0.1)
+            self.plot_item.setRange(
+                xRange=(self.plot_sequence[1], len(self.intensity_monitor)),
+                yRange=(
+                    0,
+                    np.max(self.intensity_monitor[self.plot_sequence[1] :]),
+                ),
+                padding=0.1,
+            )
 
     @Slot(str)
     def handle_calibration_assessment_update(self, value):
@@ -1424,12 +1832,18 @@ def handle_calibration_assessment_update(self, value):
     def handle_calibration_assessment_msg_update(self, value):
         self.ui.tb_calib_assessment.setText(value)
 
-        if self.calib_assessment_level == 'good':
-            self.ui.tb_calib_assessment.setStyleSheet("border: 1px solid green;")
-        elif self.calib_assessment_level == 'okay':
-            self.ui.tb_calib_assessment.setStyleSheet("border: 1px solid rgb(252,190,3);")
-        elif self.calib_assessment_level == 'bad':
-            self.ui.tb_calib_assessment.setStyleSheet("border: 1px solid rgb(200,0,0);")
+        if self.calib_assessment_level == "good":
+            self.ui.tb_calib_assessment.setStyleSheet(
+                "border: 1px solid green;"
+            )
+        elif self.calib_assessment_level == "okay":
+            self.ui.tb_calib_assessment.setStyleSheet(
+                "border: 1px solid rgb(252,190,3);"
+            )
+        elif self.calib_assessment_level == "bad":
+            self.ui.tb_calib_assessment.setStyleSheet(
+                "border: 1px solid rgb(200,0,0);"
+            )
         else:
             pass
 
@@ -1443,99 +1857,127 @@ def handle_lc_states_emit(self, value: tuple[tuple, dict[str, list]]):
             2-tuple consisting of a tuple of polarization state names and a dictionary of LC retardance values.
         """
         pol_states, lc_values = value
-    
-        # Calculate circle 
-        theta = np.linspace(0, 2*np.pi, 100)
-        x_circ = self.swing*np.cos(theta) + lc_values["LCA"][0]
-        y_circ = self.swing*np.sin(theta) + lc_values["LCB"][0]
+
+        # Calculate circle
+        theta = np.linspace(0, 2 * np.pi, 100)
+        x_circ = self.swing * np.cos(theta) + lc_values["LCA"][0]
+        y_circ = self.swing * np.sin(theta) + lc_values["LCB"][0]
 
         import matplotlib.pyplot as plt
-        plt.close('all')
-        with plt.rc_context({
-            "axes.spines.right": False,
-            "axes.spines.top": False,
-        }) and plt.ion():
+
+        plt.close("all")
+        with plt.rc_context(
+            {
+                "axes.spines.right": False,
+                "axes.spines.top": False,
+            }
+        ) and plt.ion():
             plt.figure("Calibrated LC States")
-            plt.scatter(lc_values["LCA"], lc_values["LCB"], c='r')
-            plt.plot(x_circ, y_circ, 'k--', alpha=0.25)
+            plt.scatter(lc_values["LCA"], lc_values["LCB"], c="r")
+            plt.plot(x_circ, y_circ, "k--", alpha=0.25)
             plt.axis("equal")
             plt.xlabel("LCA retardance")
             plt.ylabel("LCB retardance")
             for i, pol in enumerate(pol_states):
                 plt.annotate(
-                    pol, 
+                    pol,
                     xy=(lc_values["LCA"][i], lc_values["LCB"][i]),
-                    xycoords='data',
-                    xytext=(10,10), # annotation offset
-                    textcoords='offset points'
-            )
+                    xycoords="data",
+                    xytext=(10, 10),  # annotation offset
+                    textcoords="offset points",
+                )
 
     @Slot(object)
     def handle_bg_image_update(self, value):
 
-        if 'Background Images' in self.viewer.layers:
-            self.viewer.layers['Background Images'].data = value
+        if "Background Images" in self.viewer.layers:
+            self.viewer.layers["Background Images"].data = value
         else:
-            self.viewer.add_image(value, name='Background Images', colormap='gray')
+            self.viewer.add_image(
+                value, name="Background Images", colormap="gray"
+            )
 
     @Slot(object)
     def handle_bg_bire_image_update(self, value):
 
         # Separate Background Retardance and Background Orientation
         # Add new layer if none exists, otherwise update layer data
-        if 'Background Retardance' in self.viewer.layers:
-            self.viewer.layers['Background Retardance'].data = value[0]
+        if "Background Retardance" in self.viewer.layers:
+            self.viewer.layers["Background Retardance"].data = value[0]
         else:
-            self.viewer.add_image(value[0], name='Background Retardance', colormap='gray')
+            self.viewer.add_image(
+                value[0], name="Background Retardance", colormap="gray"
+            )
 
-        if 'Background Orientation' in self.viewer.layers:
-            self.viewer.layers['Background Orientation'].data = value[1]
+        if "Background Orientation" in self.viewer.layers:
+            self.viewer.layers["Background Orientation"].data = value[1]
         else:
-            self.viewer.add_image(value[1], name='Background Orientation', colormap='gray')
+            self.viewer.add_image(
+                value[1], name="Background Orientation", colormap="gray"
+            )
 
     @Slot(object)
     def handle_bire_image_update(self, value):
 
-        channel_names = {'Orientation': 1,
-                         'Retardance': 0,
-                         }
+        channel_names = {
+            "Orientation": 1,
+            "Retardance": 0,
+        }
 
         # Compute Overlay if birefringence acquisition is 2D
-        if self.birefringence_dim == '2D':
-            channel_names['BirefringenceOverlay'] = None
-            overlay = ret_ori_overlay(retardance=value[0],
-                                      orientation=value[1],
-                                      ret_max= np.percentile(value[0], 99.99),
-                                      cmap=self.colormap)
+        if self.birefringence_dim == "2D":
+            channel_names["BirefringenceOverlay"] = None
+            overlay = ret_ori_overlay(
+                retardance=value[0],
+                orientation=value[1],
+                ret_max=np.percentile(value[0], 99.99),
+                cmap=self.colormap,
+            )
 
         for key, chan in channel_names.items():
-            if key == 'BirefringenceOverlay':
-                if key+self.birefringence_dim in self.viewer.layers:
-                    self.viewer.layers[key+self.birefringence_dim].data = overlay
+            if key == "BirefringenceOverlay":
+                if key + self.birefringence_dim in self.viewer.layers:
+                    self.viewer.layers[
+                        key + self.birefringence_dim
+                    ].data = overlay
                 else:
-                    self.viewer.add_image(overlay, name=key+self.birefringence_dim, rgb=True)
+                    self.viewer.add_image(
+                        overlay, name=key + self.birefringence_dim, rgb=True
+                    )
             else:
-                if key+self.birefringence_dim in self.viewer.layers:
-                    self.viewer.layers[key+self.birefringence_dim].data = value[chan]
+                if key + self.birefringence_dim in self.viewer.layers:
+                    self.viewer.layers[
+                        key + self.birefringence_dim
+                    ].data = value[chan]
                 else:
-                    cmap = 'gray' if key != 'Orientation' else 'hsv'
-                    self.viewer.add_image(value[chan], name=key+self.birefringence_dim, colormap=cmap)
+                    cmap = "gray" if key != "Orientation" else "hsv"
+                    self.viewer.add_image(
+                        value[chan],
+                        name=key + self.birefringence_dim,
+                        colormap=cmap,
+                    )
 
     @Slot(object)
     def handle_phase_image_update(self, value):
 
-        name = 'Phase2D' if self.phase_dim == '2D' else 'Phase3D'
+        name = "Phase2D" if self.phase_dim == "2D" else "Phase3D"
 
         # Add new layer if none exists, otherwise update layer data
         if name in self.viewer.layers:
             self.viewer.layers[name].data = value
         else:
-            self.viewer.add_image(value, name=name, colormap='gray')
-
-        if 'Phase' not in [self.ui.cb_saturation.itemText(i) for i in range(self.ui.cb_saturation.count())]:
-            self.ui.cb_saturation.addItem('Retardance')
-        if 'Phase' not in [self.ui.cb_value.itemText(i) for i in range(self.ui.cb_value.count())]:
-            self.ui.cb_value.addItem('Retardance')
+            self.viewer.add_image(value, name=name, colormap="gray")
+
+        if "Phase" not in [
+            self.ui.cb_saturation.itemText(i)
+            for i in range(self.ui.cb_saturation.count())
+        ]:
+            self.ui.cb_saturation.addItem("Retardance")
+        if "Phase" not in [
+            self.ui.cb_value.itemText(i)
+            for i in range(self.ui.cb_value.count())
+        ]:
+            self.ui.cb_value.addItem("Retardance")
 
     @Slot(object)
     def handle_qlipp_reconstructor_update(self, value):
@@ -1593,19 +2035,27 @@ def handle_reconstruction_dim_update(self, value):
         layer_name = self.worker.manager.config.data_save_name
 
         if p == 0 and t == 0 and c == 0:
-            self.reconstruction_data = WaveorderReader(self.reconstruction_data_path, 'zarr')
-            self.viewer.add_image(self.reconstruction_data.get_zarr(p), name=layer_name + f'_Pos_{p:03d}')
-
-            self.viewer.dims.set_axis_label(0, 'T')
-            self.viewer.dims.set_axis_label(1, 'C')
-            self.viewer.dims.set_axis_label(2, 'Z')
+            self.reconstruction_data = WaveorderReader(
+                self.reconstruction_data_path, "zarr"
+            )
+            self.viewer.add_image(
+                self.reconstruction_data.get_zarr(p),
+                name=layer_name + f"_Pos_{p:03d}",
+            )
 
+            self.viewer.dims.set_axis_label(0, "T")
+            self.viewer.dims.set_axis_label(1, "C")
+            self.viewer.dims.set_axis_label(2, "Z")
 
         # Add each new position as a new layer in napari
-        name = layer_name + f'_Pos_{p:03d}'
+        name = layer_name + f"_Pos_{p:03d}"
         if name not in self.viewer.layers:
-            self.reconstruction_data = WaveorderReader(self.reconstruction_data_path, 'zarr')
-            self.viewer.add_image(self.reconstruction_data.get_zarr(p), name=name)
+            self.reconstruction_data = WaveorderReader(
+                self.reconstruction_data_path, "zarr"
+            )
+            self.viewer.add_image(
+                self.reconstruction_data.get_zarr(p), name=name
+            )
 
         # update the napari dimension slider position if the user hasn't specified to pause updates
         if not self.pause_updates:
@@ -1616,7 +2066,7 @@ def handle_reconstruction_dim_update(self, value):
 
     @Slot(bool)
     def browse_dir_path(self):
-        result = self._open_file_dialog(self.current_dir_path, 'dir')
+        result = self._open_file_dialog(self.current_dir_path, "dir")
         self.directory = result
         self.current_dir_path = result
         self.ui.le_directory.setText(result)
@@ -1625,20 +2075,20 @@ def browse_dir_path(self):
 
     @Slot(bool)
     def browse_save_path(self):
-        result = self._open_file_dialog(self.current_save_path, 'dir')
+        result = self._open_file_dialog(self.current_save_path, "dir")
         self.save_directory = result
         self.current_save_path = result
         self.ui.le_save_dir.setText(result)
 
     @Slot(bool)
     def browse_data_dir(self):
-        path = self._open_file_dialog(self.data_dir, 'dir')
+        path = self._open_file_dialog(self.data_dir, "dir")
         self.data_dir = path
         self.ui.le_data_dir.setText(self.data_dir)
 
     @Slot(bool)
     def browse_calib_meta(self):
-        path = self._open_file_dialog(self.calib_path, 'file')
+        path = self._open_file_dialog(self.calib_path, "file")
         self.calib_path = path
         self.ui.le_calibration_metadata.setText(self.calib_path)
 
@@ -1650,7 +2100,7 @@ def enter_dir_path(self):
             self.save_directory = path
             self.ui.le_save_dir.setText(path)
         else:
-            self.ui.le_directory.setText('Path Does Not Exist')
+            self.ui.le_directory.setText("Path Does Not Exist")
 
     @Slot()
     def enter_swing(self):
@@ -1664,27 +2114,27 @@ def enter_wavelength(self):
     def enter_calib_scheme(self):
         index = self.ui.cb_calib_scheme.currentIndex()
         if index == 0:
-            self.calib_scheme = '4-State'
+            self.calib_scheme = "4-State"
         else:
-            self.calib_scheme = '5-State'
+            self.calib_scheme = "5-State"
 
     @Slot()
     def enter_calib_mode(self):
         index = self.ui.cb_calib_mode.currentIndex()
         if index == 0:
-            self.calib_mode = 'MM-Retardance'
+            self.calib_mode = "MM-Retardance"
             self.ui.label_lca.hide()
             self.ui.label_lcb.hide()
             self.ui.cb_lca.hide()
             self.ui.cb_lcb.hide()
         elif index == 1:
-            self.calib_mode = 'MM-Voltage'
+            self.calib_mode = "MM-Voltage"
             self.ui.label_lca.hide()
             self.ui.label_lcb.hide()
             self.ui.cb_lca.hide()
             self.ui.cb_lcb.hide()
         elif index == 2:
-            self.calib_mode = 'DAC'
+            self.calib_mode = "DAC"
             self.ui.cb_lca.clear()
             self.ui.cb_lcb.clear()
             self.ui.cb_lca.show()
@@ -1692,18 +2142,18 @@ def enter_calib_mode(self):
             self.ui.label_lca.show()
             self.ui.label_lcb.show()
 
-            cfg = self.mmc.getConfigData(self.config_group, 'State0')
+            cfg = self.mmc.getConfigData(self.config_group, "State0")
 
             # Update the DAC combo boxes with available DAC's from the config.  Necessary for the user
             # to specify which DAC output corresponds to which LC for voltage-space calibration
             memory = set()
             for i in range(cfg.size()):
                 prop = cfg.getSetting(i)
-                if 'TS_DAC' in prop.getDeviceLabel():
+                if "TS_DAC" in prop.getDeviceLabel():
                     dac = prop.getDeviceLabel()[-2:]
                     if dac not in memory:
-                        self.ui.cb_lca.addItem('DAC'+dac)
-                        self.ui.cb_lcb.addItem('DAC'+dac)
+                        self.ui.cb_lca.addItem("DAC" + dac)
+                        self.ui.cb_lcb.addItem("DAC" + dac)
                         memory.add(dac)
                     else:
                         continue
@@ -1731,7 +2181,7 @@ def enter_config_group(self):
         -------
 
         """
-        #if/else takes care of the clearing of config
+        # if/else takes care of the clearing of config
         if self.ui.cb_config_group.count() != 0:
             self.mmc = self.bridge.get_core()
             self.mm = self.bridge.get_studio()
@@ -1740,12 +2190,12 @@ def enter_config_group(self):
             self.config_group = self.ui.cb_config_group.currentText()
             config = self.mmc.getAvailableConfigs(self.config_group)
 
-            channels = [] 
+            channels = []
             for i in range(config.size()):
                 channels.append(config.get(i))
 
             # Check to see if any states are missing
-            states = ['State0', 'State1', 'State2', 'State3', 'State4']
+            states = ["State0", "State1", "State2", "State3", "State4"]
             missing = []
             for state in states:
                 if state not in channels:
@@ -1753,14 +2203,18 @@ def enter_config_group(self):
 
             # if states are missing, set the combo box red and alert the user
             if len(missing) != 0:
-                msg = f'The chosen config group ({self.config_group}) is missing states: {missing}. '\
-                    'Please refer to the recOrder wiki on how to set up the config properly.'
-
-                self.ui.cb_config_group.setStyleSheet("border: 1px solid rgb(200,0,0);")
+                msg = (
+                    f"The chosen config group ({self.config_group}) is missing states: {missing}. "
+                    "Please refer to the recOrder wiki on how to set up the config properly."
+                )
+
+                self.ui.cb_config_group.setStyleSheet(
+                    "border: 1px solid rgb(200,0,0);"
+                )
                 raise KeyError(msg)
             else:
                 self.ui.cb_config_group.setStyleSheet("")
-       
+
     @Slot()
     def enter_use_cropped_roi(self):
         state = self.ui.chb_use_roi.checkState()
@@ -1792,7 +2246,7 @@ def enter_save_path(self):
             self.save_directory = path
             self.current_save_path = path
         else:
-            self.ui.le_save_dir.setText('Path Does Not Exist')
+            self.ui.le_save_dir.setText("Path Does Not Exist")
 
     @Slot()
     def enter_save_name(self):
@@ -1815,17 +2269,17 @@ def enter_zstep(self):
     def enter_birefringence_dim(self):
         state = self.ui.cb_birefringence.currentIndex()
         if state == 0:
-            self.birefringence_dim = '2D'
+            self.birefringence_dim = "2D"
         elif state == 1:
-            self.birefringence_dim = '3D'
+            self.birefringence_dim = "3D"
 
     @Slot()
     def enter_phase_dim(self):
         state = self.ui.cb_phase.currentIndex()
         if state == 0:
-            self.phase_dim = '2D'
+            self.phase_dim = "2D"
         elif state == 1:
-            self.phase_dim = '3D'
+            self.phase_dim = "3D"
 
     @Slot()
     def enter_phase_denoiser(self):
@@ -1849,7 +2303,7 @@ def enter_acq_bg_path(self):
             self.acq_bg_directory = path
             self.current_bg_path = path
         else:
-            self.ui.le_bg_path.setText('Path Does Not Exist')
+            self.ui.le_bg_path.setText("Path Does Not Exist")
 
     @Slot(str)
     def handle_bg_path_update(self, value: str):
@@ -1876,7 +2330,7 @@ def handle_bg_path_update(self, value: str):
 
     @Slot(bool)
     def browse_acq_bg_path(self):
-        result = self._open_file_dialog(self.current_bg_path, 'dir')
+        result = self._open_file_dialog(self.current_bg_path, "dir")
         self.acq_bg_directory = result
         self.current_bg_path = result
         self.ui.le_bg_path.setText(result)
@@ -1888,22 +2342,22 @@ def enter_bg_correction(self):
             self.ui.label_bg_path.setHidden(True)
             self.ui.le_bg_path.setHidden(True)
             self.ui.qbutton_browse_bg_path.setHidden(True)
-            self.bg_option = 'None'
+            self.bg_option = "None"
         elif state == 1:
             self.ui.label_bg_path.setHidden(False)
             self.ui.le_bg_path.setHidden(False)
             self.ui.qbutton_browse_bg_path.setHidden(False)
-            self.bg_option = 'global'
+            self.bg_option = "global"
         elif state == 2:
             self.ui.label_bg_path.setHidden(True)
             self.ui.le_bg_path.setHidden(True)
             self.ui.qbutton_browse_bg_path.setHidden(True)
-            self.bg_option = 'local_fit'
+            self.bg_option = "local_fit"
         elif state == 3:
             self.ui.label_bg_path.setHidden(False)
             self.ui.le_bg_path.setHidden(False)
             self.ui.qbutton_browse_bg_path.setHidden(False)
-            self.bg_option = 'local_fit+'
+            self.bg_option = "local_fit+"
 
     @Slot()
     def enter_gpu_id(self):
@@ -1969,29 +2423,31 @@ def enter_method(self):
         idx = self.ui.cb_method.currentIndex()
 
         if idx == 0:
-            self.method = 'QLIPP'
+            self.method = "QLIPP"
             self.ui.label_bf_chan.hide()
             self.ui.le_bf_chan.hide()
-            self.ui.label_chan_desc.setText('Retardance, Orientation, BF, Phase3D, Phase2D, S0, S1, S2, S3')
+            self.ui.label_chan_desc.setText(
+                "Retardance, Orientation, BF, Phase3D, Phase2D, S0, S1, S2, S3"
+            )
 
         elif idx == 1:
-            self.method = 'PhaseFromBF'
+            self.method = "PhaseFromBF"
             self.ui.label_bf_chan.show()
             self.ui.le_bf_chan.show()
-            self.ui.label_bf_chan.setText('Brightfield Channel Index')
-            self.ui.le_bf_chan.setPlaceholderText('int')
-            self.ui.label_chan_desc.setText('Phase3D, Phase2D')
+            self.ui.label_bf_chan.setText("Brightfield Channel Index")
+            self.ui.le_bf_chan.setPlaceholderText("int")
+            self.ui.label_chan_desc.setText("Phase3D, Phase2D")
 
     @Slot(int)
     def enter_mode(self):
         idx = self.ui.cb_mode.currentIndex()
 
         if idx == 0:
-            self.mode = '3D'
+            self.mode = "3D"
             self.ui.label_focus_zidx.hide()
             self.ui.le_focus_zidx.hide()
         else:
-            self.mode = '2D'
+            self.mode = "2D"
             self.ui.label_focus_zidx.show()
             self.ui.le_focus_zidx.show()
 
@@ -1999,8 +2455,10 @@ def enter_mode(self):
     def enter_data_dir(self):
         entry = self.ui.le_data_dir.text()
         if not os.path.exists(entry):
-            self.ui.le_data_dir.setStyleSheet("border: 1px solid rgb(200,0,0);")
-            self.ui.le_data_dir.setText('Path Does Not Exist')
+            self.ui.le_data_dir.setStyleSheet(
+                "border: 1px solid rgb(200,0,0);"
+            )
+            self.ui.le_data_dir.setText("Path Does Not Exist")
         else:
             self.ui.le_data_dir.setStyleSheet("")
             self.data_dir = entry
@@ -2009,8 +2467,10 @@ def enter_data_dir(self):
     def enter_calib_meta(self):
         entry = self.ui.le_calibration_metadata.text()
         if not os.path.exists(entry):
-            self.ui.le_calibration_metadata.setStyleSheet("border: 1px solid rgb(200,0,0);")
-            self.ui.le_calibration_metadata.setText('Path Does Not Exist')
+            self.ui.le_calibration_metadata.setStyleSheet(
+                "border: 1px solid rgb(200,0,0);"
+            )
+            self.ui.le_calibration_metadata.setText("Path Does Not Exist")
         else:
             self.ui.le_calibration_metadata.setStyleSheet("")
             self.calib_path = entry
@@ -2030,23 +2490,30 @@ def enter_colormap(self):
         state = self.ui.cb_colormap.currentIndex()
         if state == 0:
             self.ui.label_orientation_image.setPixmap(self.jch_pixmap)
-            self.colormap = 'JCh'
+            self.colormap = "JCh"
         else:
             self.ui.label_orientation_image.setPixmap(self.hsv_pixmap)
-            self.colormap = 'HSV'
+            self.colormap = "HSV"
 
         # Update the birefringence overlay to new colormap if the colormap has changed
         if prev_cmap != self.colormap:
-            #TODO: Handle case where there are multiple snaps
-            if 'BirefringenceOverlay2D' in self.viewer.layers:
-                if 'Retardance2D' in self.viewer.layers and 'Orientation2D' in self.viewer.layers:
-
-                    overlay = ret_ori_overlay(retardance=self.viewer.layers['Retardance2D'].data,
-                                              orientation=self.viewer.layers['Orientation2D'].data,
-                                              ret_max= np.percentile(self.viewer.layers['Retardance2D'].data, 99.99),
-                                              cmap=self.colormap)
-
-                    self.viewer.layers['BirefringenceOverlay2D'].data = overlay
+            # TODO: Handle case where there are multiple snaps
+            if "BirefringenceOverlay2D" in self.viewer.layers:
+                if (
+                    "Retardance2D" in self.viewer.layers
+                    and "Orientation2D" in self.viewer.layers
+                ):
+
+                    overlay = ret_ori_overlay(
+                        retardance=self.viewer.layers["Retardance2D"].data,
+                        orientation=self.viewer.layers["Orientation2D"].data,
+                        ret_max=np.percentile(
+                            self.viewer.layers["Retardance2D"].data, 99.99
+                        ),
+                        cmap=self.colormap,
+                    )
+
+                    self.viewer.layers["BirefringenceOverlay2D"].data = overlay
 
     @Slot(int)
     def enter_use_full_volume(self):
@@ -2101,24 +2568,26 @@ def push_note(self):
 
         # make sure the user has performed a calibration in this session (or loaded a previous one)
         if not self.last_calib_meta_file:
-            raise ValueError('No calibration has been performed yet so there is no previous metadata file')
+            raise ValueError(
+                "No calibration has been performed yet so there is no previous metadata file"
+            )
         else:
             note = self.ui.le_notes_field.text()
 
             # Open the existing calibration metadata file and append the notes
-            with open(self.last_calib_meta_file, 'r') as file:
+            with open(self.last_calib_meta_file, "r") as file:
                 current_json = json.load(file)
 
             # Append note to the end of the old note (so we don't overwrite previous notes) or write a new
             # note in the blank notes field
-            old_note = current_json['Notes']
-            if old_note is None or old_note == '' or old_note == note:
-                current_json['Notes'] = note
+            old_note = current_json["Notes"]
+            if old_note is None or old_note == "" or old_note == note:
+                current_json["Notes"] = note
             else:
-                current_json['Notes'] = old_note + ', ' + note
+                current_json["Notes"] = old_note + ", " + note
 
             # dump the contents into the metadata file
-            with open(self.last_calib_meta_file, 'w') as file:
+            with open(self.last_calib_meta_file, "w") as file:
                 json.dump(current_json, file, indent=1)
 
     @Slot(bool)
@@ -2134,13 +2603,15 @@ def calc_extinction(self):
         """
 
         # Snap images from the extinction state and first elliptical state
-        set_lc_state(self.mmc, self.config_group, 'State0')
+        set_lc_state(self.mmc, self.config_group, "State0")
         extinction = snap_and_average(self.calib.snap_manager)
-        set_lc_state(self.mmc, self.config_group, 'State1')
+        set_lc_state(self.mmc, self.config_group, "State1")
         state1 = snap_and_average(self.calib.snap_manager)
 
         # Calculate extinction based off captured intensities
-        extinction = self.calib.calculate_extinction(self.swing, self.calib.I_Black, extinction, state1)
+        extinction = self.calib.calculate_extinction(
+            self.swing, self.calib.I_Black, extinction, state1
+        )
         self.ui.le_extinction.setText(str(extinction))
 
     @property
@@ -2149,19 +2620,20 @@ def _microscope_params(self):
         A dictionary containing microscope parameters from the current GUI
         Unused in 0.2.0 --- candidate for deletion
         """
+
         def _param_value(param_name: str, ui=self.ui):
             # refer to main widget class ui attribute names
             ui_attr_name = "le_" + param_name
             param_text = ui.__getattribute__(ui_attr_name).text()
             # handle blank string
-            return float(param_text) if param_text != '' else None
+            return float(param_text) if param_text != "" else None
 
         return {
-            'n_objective_media': _param_value("n_media"),
-            'objective_NA': _param_value("obj_na"),
-            'condenser_NA': _param_value("cond_na"),
-            'magnification': _param_value("mag"),
-            'pixel_size': _param_value("ps")
+            "n_objective_media": _param_value("n_media"),
+            "objective_NA": _param_value("obj_na"),
+            "condenser_NA": _param_value("cond_na"),
+            "magnification": _param_value("mag"),
+            "pixel_size": _param_value("ps"),
         }
 
     @Slot(bool)
@@ -2170,7 +2642,7 @@ def load_calibration(self):
         Uses previous JSON calibration metadata to load previous calibration
         """
 
-        metadata_path = self._open_file_dialog(self.current_dir_path, 'file')
+        metadata_path = self._open_file_dialog(self.current_dir_path, "file")
         metadata = MetadataReader(metadata_path)
 
         # Update Properties
@@ -2178,15 +2650,21 @@ def load_calibration(self):
         self.swing = metadata.Swing
 
         # Initialize calibration class
-        self.calib = QLIPP_Calibration(self.mmc, self.mm, group=self.config_group, lc_control_mode=self.calib_mode,
-                                       interp_method=self.interp_method, wavelength=self.wavelength)
+        self.calib = QLIPP_Calibration(
+            self.mmc,
+            self.mm,
+            group=self.config_group,
+            lc_control_mode=self.calib_mode,
+            interp_method=self.interp_method,
+            wavelength=self.wavelength,
+        )
         self.calib.swing = self.swing
         self.ui.le_swing.setText(str(self.swing))
         self.calib.wavelength = self.wavelength
         self.ui.le_wavelength.setText(str(self.wavelength))
 
         # Update Calibration Scheme Combo Box
-        if metadata.Calibration_scheme == '4-State':
+        if metadata.Calibration_scheme == "4-State":
             self.ui.cb_calib_scheme.setCurrentIndex(0)
         else:
             self.ui.cb_calib_scheme.setCurrentIndex(1)
@@ -2218,21 +2696,27 @@ def run_calibration(self):
         """
 
         self._check_MM_config_setup()
-        
-        self.calib = QLIPP_Calibration(self.mmc, self.mm, group=self.config_group, lc_control_mode=self.calib_mode,
-                                       interp_method=self.interp_method, wavelength=self.wavelength)
 
-        if self.calib_mode == 'DAC':
+        self.calib = QLIPP_Calibration(
+            self.mmc,
+            self.mm,
+            group=self.config_group,
+            lc_control_mode=self.calib_mode,
+            interp_method=self.interp_method,
+            wavelength=self.wavelength,
+        )
+
+        if self.calib_mode == "DAC":
             self.calib.set_dacs(self.lca_dac, self.lcb_dac)
 
         # Reset Styling
-        self.ui.tb_calib_assessment.setText('')
+        self.ui.tb_calib_assessment.setText("")
         self.ui.tb_calib_assessment.setStyleSheet("")
 
         # Save initial autoshutter state for when we set it back later
         self.auto_shutter = self.mmc.getAutoShutter()
 
-        logging.info('Starting Calibration')
+        logging.info("Starting Calibration")
 
         # Initialize displays + parameters for calibration
         self.ui.progress_bar.setValue(0)
@@ -2240,7 +2724,9 @@ def run_calibration(self):
         self.intensity_monitor = []
         self.calib.swing = self.swing
         self.calib.wavelength = self.wavelength
-        self.calib.meta_file = os.path.join(self.directory, 'calibration_metadata.txt')
+        self.calib.meta_file = os.path.join(
+            self.directory, "calibration_metadata.txt"
+        )
 
         # Make sure Live Mode is off
         if self.calib.snap_manager.getIsLiveModeOn():
@@ -2253,10 +2739,16 @@ def run_calibration(self):
         self.worker.progress_update.connect(self.handle_progress_update)
         self.worker.extinction_update.connect(self.handle_extinction_update)
         self.worker.intensity_update.connect(self.handle_plot_update)
-        self.worker.calib_assessment.connect(self.handle_calibration_assessment_update)
-        self.worker.calib_assessment_msg.connect(self.handle_calibration_assessment_msg_update)
+        self.worker.calib_assessment.connect(
+            self.handle_calibration_assessment_update
+        )
+        self.worker.calib_assessment_msg.connect(
+            self.handle_calibration_assessment_msg_update
+        )
         self.worker.calib_file_emit.connect(self.handle_calib_file_update)
-        self.worker.plot_sequence_emit.connect(self.handle_plot_sequence_update)
+        self.worker.plot_sequence_emit.connect(
+            self.handle_plot_sequence_update
+        )
         self.worker.lc_states.connect(self.handle_lc_states_emit)
         self.worker.started.connect(self._disable_buttons)
         self.worker.finished.connect(self._enable_buttons)
@@ -2268,38 +2760,59 @@ def run_calibration(self):
     @property
     def _channel_descriptions(self):
         return [
-            self.mmc.getConfigData(self.config_group, calib_channel).getVerbose() 
+            self.mmc.getConfigData(
+                self.config_group, calib_channel
+            ).getVerbose()
             for calib_channel in self.calib_channels
         ]
 
     def _check_MM_config_setup(self):
         # Warns the user if the MM configuration is not correctly set up.
         desc = self._channel_descriptions
-        if self.calib_mode == 'MM-Retardance':
-            if all('String send to' in s for s in desc) and not any('Voltage (V)' in s for s in desc):
+        if self.calib_mode == "MM-Retardance":
+            if all("String send to" in s for s in desc) and not any(
+                "Voltage (V)" in s for s in desc
+            ):
                 return
             else:
-                msg = ' \n'.join(textwrap.wrap("In \'MM-Retardance\' mode each preset must include the " \
-                    "\'String send to\' property, and no \'Voltage\' properties.", width=40))
+                msg = " \n".join(
+                    textwrap.wrap(
+                        "In 'MM-Retardance' mode each preset must include the "
+                        "'String send to' property, and no 'Voltage' properties.",
+                        width=40,
+                    )
+                )
                 show_warning(msg)
-       
-        elif self.calib_mode == 'MM-Voltage':
-            if all('Voltage (V) LC-A' in s for s in desc) and all('Voltage (V) LC-B' in s for s in desc) and not any('String send to' in s for s in desc):
+
+        elif self.calib_mode == "MM-Voltage":
+            if (
+                all("Voltage (V) LC-A" in s for s in desc)
+                and all("Voltage (V) LC-B" in s for s in desc)
+                and not any("String send to" in s for s in desc)
+            ):
                 return
             else:
-                msg = ' \n'.join(textwrap.wrap("In \'MM-Voltage\' mode each preset must include the \'Voltage (V) LC-A\' " \
-                    "property, the \'Voltage (V) LC-B\' property, and no \'String send to\' properties.", width=40))
+                msg = " \n".join(
+                    textwrap.wrap(
+                        "In 'MM-Voltage' mode each preset must include the 'Voltage (V) LC-A' "
+                        "property, the 'Voltage (V) LC-B' property, and no 'String send to' properties.",
+                        width=40,
+                    )
+                )
                 show_warning(msg)
 
-        elif self.calib_mode == 'DAC':
+        elif self.calib_mode == "DAC":
             _devices = self.mmc.getLoadedDevices()
             loaded_devices = [_devices.get(i) for i in range(_devices.size())]
             if LC_DEVICE_NAME in loaded_devices:
-                show_warning("In \'DAC\' mode the MeadowLarkLC device adapter must not be loaded in MM.")
-        
+                show_warning(
+                    "In 'DAC' mode the MeadowLarkLC device adapter must not be loaded in MM."
+                )
+
         else:
-            raise ValueError(f'self.calib_mode = {self.calib_mode} is an unrecognized state.')
-        
+            raise ValueError(
+                f"self.calib_mode = {self.calib_mode} is an unrecognized state."
+            )
 
     @Slot(bool)
     def capture_bg(self):
@@ -2316,20 +2829,22 @@ def capture_bg(self):
             no_calibration_message = """Capturing a background requires calibrated liquid crystals. \
                 Please either run a calibration or load a calibration from file."""
             raise RuntimeError(no_calibration_message)
-            
+
         # Init worker and thread
         self.worker = BackgroundCaptureWorker(self, self.calib)
 
         # Connect Handlers
         self.worker.bg_image_emitter.connect(self.handle_bg_image_update)
-        self.worker.bire_image_emitter.connect(self.handle_bg_bire_image_update)
+        self.worker.bire_image_emitter.connect(
+            self.handle_bg_bire_image_update
+        )
 
         self.worker.started.connect(self._disable_buttons)
         self.worker.finished.connect(self._enable_buttons)
         self.worker.errored.connect(self._handle_error)
         self.ui.qbutton_stop_calib.clicked.connect(self.worker.quit)
         self.worker.aborted.connect(self._handle_calib_abort)
-        
+
         # Connect to BG Correction Path
         self.worker.bg_path_update_emitter.connect(self.handle_bg_path_update)
 
@@ -2345,10 +2860,12 @@ def acq_birefringence(self):
 
         """
 
-        self._check_requirements_for_acq('birefringence')
+        self._check_requirements_for_acq("birefringence")
 
         # Init Worker and thread
-        self.worker = PolarizationAcquisitionWorker(self, self.calib, 'birefringence')
+        self.worker = PolarizationAcquisitionWorker(
+            self, self.calib, "birefringence"
+        )
 
         # Connect Handlers
         self.worker.bire_image_emitter.connect(self.handle_bire_image_update)
@@ -2366,17 +2883,21 @@ def acq_phase(self):
         Wrapper function to acquire phase stack and plot in napari
         """
 
-        self._check_requirements_for_acq('phase')
+        self._check_requirements_for_acq("phase")
 
         # Init worker and thread
         if self.ui.chb_phase_from_bf.isChecked():
             self.worker = BFAcquisitionWorker(self)
         else:
-            self.worker = PolarizationAcquisitionWorker(self, self.calib, 'phase')
+            self.worker = PolarizationAcquisitionWorker(
+                self, self.calib, "phase"
+            )
 
         # Connect Handlers
         self.worker.phase_image_emitter.connect(self.handle_phase_image_update)
-        self.worker.phase_reconstructor_emitter.connect(self.handle_qlipp_reconstructor_update)
+        self.worker.phase_reconstructor_emitter.connect(
+            self.handle_qlipp_reconstructor_update
+        )
         self.worker.meta_emitter.connect(self.handle_meta_update)
         self.worker.started.connect(self._disable_buttons)
         self.worker.finished.connect(self._enable_buttons)
@@ -2391,15 +2912,17 @@ def acq_birefringence_phase(self):
         Wrapper function to acquire both birefringence and phase stack and plot in napari
         """
 
-        self._check_requirements_for_acq('phase')
+        self._check_requirements_for_acq("phase")
 
         # Init worker
         # Init worker and thread
-        self.worker = PolarizationAcquisitionWorker(self, self.calib, 'all')
+        self.worker = PolarizationAcquisitionWorker(self, self.calib, "all")
 
         # connect handlers
         self.worker.phase_image_emitter.connect(self.handle_phase_image_update)
-        self.worker.phase_reconstructor_emitter.connect(self.handle_qlipp_reconstructor_update)
+        self.worker.phase_reconstructor_emitter.connect(
+            self.handle_qlipp_reconstructor_update
+        )
         self.worker.bire_image_emitter.connect(self.handle_bire_image_update)
         self.worker.meta_emitter.connect(self.handle_meta_update)
         self.worker.started.connect(self._disable_buttons)
@@ -2422,12 +2945,14 @@ def listen_and_reconstruct(self):
         """
 
         # Init reconstructor
-        if self.bg_option != 'None':
+        if self.bg_option != "None":
             metadata_file = get_last_metadata_file(self.current_bg_path)
             metadata = MetadataReader(metadata_file)
             roi = metadata.ROI
             height, width = roi[2], roi[3]
-            bg_data = load_bg(self.current_bg_path, height, width, roi) # TODO: remove ROI for 1.0.0
+            bg_data = load_bg(
+                self.current_bg_path, height, width, roi
+            )  # TODO: remove ROI for 1.0.0
         else:
             bg_data = None
 
@@ -2454,14 +2979,20 @@ def reconstruct(self):
 
         success = self._check_requirements_for_reconstruction()
         if not success:
-            raise ValueError('Please make sure all necessary parameters are set before reconstruction')
+            raise ValueError(
+                "Please make sure all necessary parameters are set before reconstruction"
+            )
 
         self._populate_config_from_app()
         self.worker = ReconstructionWorker(self, self.config_reader)
 
         # connect handlers
-        self.worker.dimension_emitter.connect(self.handle_reconstruction_dim_update)
-        self.worker.store_emitter.connect(self.handle_reconstruction_store_update)
+        self.worker.dimension_emitter.connect(
+            self.handle_reconstruction_dim_update
+        )
+        self.worker.store_emitter.connect(
+            self.handle_reconstruction_store_update
+        )
         self.worker.started.connect(self._disable_buttons)
         self.worker.finished.connect(self._enable_buttons)
         self.worker.errored.connect(self._handle_acq_error)
@@ -2471,7 +3002,7 @@ def reconstruct(self):
 
     @Slot(bool)
     def save_config(self):
-        path = self._open_file_dialog(self.save_config_path, 'save')
+        path = self._open_file_dialog(self.save_config_path, "save")
         self.save_config_path = path
         name = PurePath(self.save_config_path).name
         dir_ = self.save_config_path.strip(name)
@@ -2479,10 +3010,12 @@ def save_config(self):
 
         if isinstance(self.config_reader.positions, tuple):
             pos = self.config_reader.positions
-            self.config_reader.positions = f'[!!python/tuple [{pos[0]},{pos[1]}]]'
+            self.config_reader.positions = (
+                f"[!!python/tuple [{pos[0]},{pos[1]}]]"
+            )
         if isinstance(self.config_reader.timepoints, tuple):
             t = self.config_reader.timepoints
-            self.config_reader.timepoints = f'[!!python/tuple [{t[0]},{t[1]}]]'
+            self.config_reader.timepoints = f"[!!python/tuple [{t[0]},{t[1]}]]"
 
         self.config_reader.save_yaml(dir_=dir_, name=name)
 
@@ -2495,8 +3028,8 @@ def load_config(self):
         -------
 
         """
-        path = self._open_file_dialog(self.save_config_path, 'file')
-        if path == '':
+        path = self._open_file_dialog(self.save_config_path, "file")
+        if path == "":
             pass
         else:
             self.config_path = path
@@ -2517,7 +3050,7 @@ def update_sat_scale(self):
             min_, max_ = np.min(data), np.max(data)
             self.ui.slider_saturation.setMinimum(min_)
             self.ui.slider_saturation.setMaximum(max_)
-            self.ui.slider_saturation.setSingleStep((max_ - min_)/250)
+            self.ui.slider_saturation.setSingleStep((max_ - min_) / 250)
             self.ui.slider_saturation.setValue((min_, max_))
             self.ui.le_sat_max.setText(str(np.round(max_, 3)))
             self.ui.le_sat_min.setText(str(np.round(min_, 3)))
@@ -2531,7 +3064,7 @@ def update_value_scale(self):
             min_, max_ = np.min(data), np.max(data)
             self.ui.slider_value.setMinimum(min_)
             self.ui.slider_value.setMaximum(max_)
-            self.ui.slider_value.setSingleStep((max_ - min_)/250)
+            self.ui.slider_value.setSingleStep((max_ - min_) / 250)
             self.ui.slider_value.setValue((min_, max_))
             self.ui.le_val_max.setText(str(np.round(max_, 3)))
             self.ui.le_val_min.setText(str(np.round(min_, 3)))
@@ -2547,25 +3080,50 @@ def create_overlay(self):
 
         """
 
-        if self.ui.cb_hue.count() == 0 or self.ui.cb_saturation.count() == 0 or self.ui.cb_value == 0:
-            raise ValueError('Cannot create overlay until all 3 combo boxes are populated')
+        if (
+            self.ui.cb_hue.count() == 0
+            or self.ui.cb_saturation.count() == 0
+            or self.ui.cb_value == 0
+        ):
+            raise ValueError(
+                "Cannot create overlay until all 3 combo boxes are populated"
+            )
 
         # Gather channel data
-        H = self.viewer.layers[self.ui.cb_hue.itemText(self.ui.cb_hue.currentIndex())].data
-        S = self.viewer.layers[self.ui.cb_saturation.itemText(self.ui.cb_saturation.currentIndex())].data
-        V = self.viewer.layers[self.ui.cb_value.itemText(self.ui.cb_value.currentIndex())].data
-
+        H = self.viewer.layers[
+            self.ui.cb_hue.itemText(self.ui.cb_hue.currentIndex())
+        ].data
+        S = self.viewer.layers[
+            self.ui.cb_saturation.itemText(
+                self.ui.cb_saturation.currentIndex()
+            )
+        ].data
+        V = self.viewer.layers[
+            self.ui.cb_value.itemText(self.ui.cb_value.currentIndex())
+        ].data
 
-        #TODO: this is a temp fix which handles on data with n-dimensions of 4, 3, or 2 which automatically
+        # TODO: this is a temp fix which handles on data with n-dimensions of 4, 3, or 2 which automatically
         # chooses the first timepoint
         if H.ndim > 2 or S.ndim > 2 or V.ndim > 2:
             if H.ndim == 4:
                 # assumes this is a (T, Z, Y, X) array read from napari-ome-zarr
-                H = H[0, self.display_slice] if not self.use_full_volume else H[0]
+                H = (
+                    H[0, self.display_slice]
+                    if not self.use_full_volume
+                    else H[0]
+                )
             if S.ndim == 4:
-                S = S[0, self.display_slice] if not self.use_full_volume else S[0]
+                S = (
+                    S[0, self.display_slice]
+                    if not self.use_full_volume
+                    else S[0]
+                )
             if V.ndim == 4:
-                V = V[0, self.display_slice] if not self.use_full_volume else V[0]
+                V = (
+                    V[0, self.display_slice]
+                    if not self.use_full_volume
+                    else V[0]
+                )
 
             if H.ndim == 3:
                 # assumes this is a (Z, Y, X) array collected from acquisition module
@@ -2577,31 +3135,37 @@ def create_overlay(self):
             if S.ndim == 3:
                 S = S[self.display_slice] if not self.use_full_volume else S
 
-        mode = '2D' if not self.use_full_volume else '3D'
+        mode = "2D" if not self.use_full_volume else "3D"
 
         H_name = self.ui.cb_hue.itemText(self.ui.cb_hue.currentIndex())
-        H_scale = (np.min(H), np.max(H)) if 'Orientation' not in H_name else (0, np.pi)
+        H_scale = (
+            (np.min(H), np.max(H))
+            if "Orientation" not in H_name
+            else (0, np.pi)
+        )
         S_scale = self.ui.slider_saturation.value()
         V_scale = self.ui.slider_value.value()
 
-        hsv_image = generic_hsv_overlay(H, S, V, H_scale, S_scale, V_scale, mode=mode)
+        hsv_image = generic_hsv_overlay(
+            H, S, V, H_scale, S_scale, V_scale, mode=mode
+        )
 
         # Create overlay layer name
         idx = 0
-        while f'HSV_Overlay_{idx}' in self.viewer.layers:
+        while f"HSV_Overlay_{idx}" in self.viewer.layers:
             idx += 1
 
         # add overlay image to napari
-        self.viewer.add_image(hsv_image, name=f'HSV_Overlay_{idx}', rgb=True)
+        self.viewer.add_image(hsv_image, name=f"HSV_Overlay_{idx}", rgb=True)
 
     @Slot(object)
     def add_listener_data(self, store):
 
-        self.viewer.add_image(store['Birefringence'], name=self.worker.prefix)
-        self.viewer.dims.set_axis_label(0, 'P')
-        self.viewer.dims.set_axis_label(1, 'T')
-        self.viewer.dims.set_axis_label(2, 'C')
-        self.viewer.dims.set_axis_label(3, 'Z')
+        self.viewer.add_image(store["Birefringence"], name=self.worker.prefix)
+        self.viewer.dims.set_axis_label(0, "P")
+        self.viewer.dims.set_axis_label(1, "T")
+        self.viewer.dims.set_axis_label(2, "C")
+        self.viewer.dims.set_axis_label(3, "Z")
 
     @Slot(tuple)
     def update_dims(self, dims):
@@ -2619,9 +3183,7 @@ def _reset_listening(self):
 
     def _open_file_dialog(self, default_path, type):
 
-        return self._open_dialog("select a directory",
-                                 str(default_path),
-                                 type)
+        return self._open_dialog("select a directory", str(default_path), type)
 
     def _open_dialog(self, title, ref, type):
         """
@@ -2641,23 +3203,20 @@ def _open_dialog(self, title, ref, type):
         options = QFileDialog.Options()
 
         options |= QFileDialog.DontUseNativeDialog
-        if type == 'dir':
-            path = QFileDialog.getExistingDirectory(None,
-                                                    title,
-                                                    ref,
-                                                    options=options)
-        elif type == 'file':
-            path = QFileDialog.getOpenFileName(None,
-                                               title,
-                                               ref,
-                                               options=options)[0]
-        elif type == 'save':
-            path = QFileDialog.getSaveFileName(None,
-                                               'Choose a save name',
-                                               ref,
-                                               options=options)[0]
+        if type == "dir":
+            path = QFileDialog.getExistingDirectory(
+                None, title, ref, options=options
+            )
+        elif type == "file":
+            path = QFileDialog.getOpenFileName(
+                None, title, ref, options=options
+            )[0]
+        elif type == "save":
+            path = QFileDialog.getSaveFileName(
+                None, "Choose a save name", ref, options=options
+            )[0]
         else:
-            raise ValueError('Did not understand file dialogue type')
+            raise ValueError("Did not understand file dialogue type")
 
         return path
 
diff --git a/recOrder/plugin/widget/napari_plugin_entry_point.py b/recOrder/plugin/widget/napari_plugin_entry_point.py
index 23ee4576..f7fdcbf7 100644
--- a/recOrder/plugin/widget/napari_plugin_entry_point.py
+++ b/recOrder/plugin/widget/napari_plugin_entry_point.py
@@ -1,1 +1,1 @@
-from recOrder.plugin.widget.main_widget import MainWidget
\ No newline at end of file
+from recOrder.plugin.widget.main_widget import MainWidget
diff --git a/recOrder/plugin/workers/acquisition_workers.py b/recOrder/plugin/workers/acquisition_workers.py
index 4887d214..0dcb585f 100644
--- a/recOrder/plugin/workers/acquisition_workers.py
+++ b/recOrder/plugin/workers/acquisition_workers.py
@@ -1,7 +1,15 @@
 from qtpy.QtCore import Signal
-from recOrder.compute.qlipp_compute import initialize_reconstructor, \
-    reconstruct_qlipp_birefringence, reconstruct_qlipp_stokes, reconstruct_phase2D, reconstruct_phase3D
-from recOrder.acq.acq_functions import generate_acq_settings, acquire_from_settings
+from recOrder.compute.qlipp_compute import (
+    initialize_reconstructor,
+    reconstruct_qlipp_birefringence,
+    reconstruct_qlipp_stokes,
+    reconstruct_phase2D,
+    reconstruct_phase3D,
+)
+from recOrder.acq.acq_functions import (
+    generate_acq_settings,
+    acquire_from_settings,
+)
 from recOrder.io.utils import load_bg, extract_reconstruction_parameters
 from recOrder.compute import QLIPPBirefringenceCompute
 from recOrder.io.zarr_converter import ZarrConverter
@@ -42,6 +50,7 @@ class BFAcquisitionSignals(WorkerBaseSignals):
     meta_emitter = Signal(dict)
     aborted = Signal()
 
+
 class ListeningSignals(WorkerBaseSignals):
     """
     Custom Signals class that includes napari native signals
@@ -65,23 +74,39 @@ def __init__(self, calib_window):
         self.calib_window = calib_window
 
         # Init Properties
-        self.prefix = 'recOrderPluginSnap'
+        self.prefix = "recOrderPluginSnap"
         self.dm = self.calib_window.mm.displays()
-        self.dim = '2D' if self.calib_window.ui.cb_phase.currentIndex() == 0 else '3D'
+        self.dim = (
+            "2D" if self.calib_window.ui.cb_phase.currentIndex() == 0 else "3D"
+        )
         self.img_dim = None
 
-        save_dir = self.calib_window.save_directory if self.calib_window.save_directory else self.calib_window.directory
+        save_dir = (
+            self.calib_window.save_directory
+            if self.calib_window.save_directory
+            else self.calib_window.directory
+        )
 
         if save_dir is None:
-            raise ValueError('save directory is empty, please specify a directory in the plugin')
+            raise ValueError(
+                "save directory is empty, please specify a directory in the plugin"
+            )
 
         # increment filename one more than last found saved snap
         i = 0
         prefix = self.calib_window.save_name
-        snap_dir = f'recOrderPluginSnap_{i}' if not prefix else f'{prefix}_recOrderPluginSnap_{i}'
+        snap_dir = (
+            f"recOrderPluginSnap_{i}"
+            if not prefix
+            else f"{prefix}_recOrderPluginSnap_{i}"
+        )
         while os.path.exists(os.path.join(save_dir, snap_dir)):
             i += 1
-            snap_dir = f'recOrderPluginSnap_{i}' if not prefix else f'{prefix}_recOrderPluginSnap_{i}'
+            snap_dir = (
+                f"recOrderPluginSnap_{i}"
+                if not prefix
+                else f"{prefix}_recOrderPluginSnap_{i}"
+            )
 
         self.snap_dir = os.path.join(save_dir, snap_dir)
         os.mkdir(self.snap_dir)
@@ -89,7 +114,7 @@ def __init__(self, calib_window):
     def _check_abort(self):
         if self.abort_requested:
             self.aborted.emit()
-            raise TimeoutError('Stop Requested')
+            raise TimeoutError("Stop Requested")
 
     def _check_ram(self):
         """
@@ -106,7 +131,7 @@ def work(self):
         Function that runs the 2D or 3D acquisition and reconstructs the data
         """
         self._check_ram()
-        logging.info('Running Acquisition...')
+        logging.info("Running Acquisition...")
         self._check_abort()
 
         channel_idx = self.calib_window.ui.cb_acq_channel.currentIndex()
@@ -126,23 +151,27 @@ def work(self):
                     break
 
         # Acquire 3D stack
-        logging.debug('Acquiring 3D stack')
+        logging.debug("Acquiring 3D stack")
 
         # Generate MDA Settings
-        settings = generate_acq_settings(self.calib_window.mm,
-                                         channel_group=channel_group,
-                                         channels=[channel],
-                                         zstart=self.calib_window.z_start,
-                                         zend=self.calib_window.z_end,
-                                         zstep=self.calib_window.z_step,
-                                         save_dir=self.snap_dir,
-                                         prefix=self.prefix)
+        settings = generate_acq_settings(
+            self.calib_window.mm,
+            channel_group=channel_group,
+            channels=[channel],
+            zstart=self.calib_window.z_start,
+            zend=self.calib_window.z_end,
+            zstep=self.calib_window.z_step,
+            save_dir=self.snap_dir,
+            prefix=self.prefix,
+        )
 
         self._check_abort()
 
         # Acquire from MDA settings uses MM MDA GUI
         # Returns (1, 4/5, Z, Y, X) array
-        stack = acquire_from_settings(self.calib_window.mm, settings, grab_images=True)
+        stack = acquire_from_settings(
+            self.calib_window.mm, settings, grab_images=True
+        )
         self._check_abort()
 
         # Cleanup acquisition by closing window, converting to zarr, and deleting temp directory
@@ -155,13 +184,13 @@ def work(self):
         self._check_abort()
 
         # Save images
-        logging.debug('Saving Images')
+        logging.debug("Saving Images")
         self._save_imgs(phase, meta)
 
         self._check_abort()
 
-        logging.info('Finished Acquisition')
-        logging.debug('Finished Acquisition')
+        logging.info("Finished Acquisition")
+        logging.debug("Finished Acquisition")
 
         # Emit the images and let thread know function is finished
         self.phase_image_emitter.emit(phase)
@@ -188,22 +217,26 @@ def _reconstruct(self, stack):
 
         # if no reconstructor has been initialized before, create new reconstructor
         if not self.calib_window.phase_reconstructor:
-            logging.debug('Computing new reconstructor')
-
-            recon = initialize_reconstructor('PhaseFromBF',
-                                             image_dim=(stack.shape[-2], stack.shape[-1]),
-                                             wavelength_nm=int(self.calib_window.ui.le_recon_wavelength.text()),
-                                             NA_obj=self.calib_window.obj_na,
-                                             NA_illu=self.calib_window.cond_na,
-                                             mag=self.calib_window.mag,
-                                             n_slices=self.img_dim[-1],
-                                             z_step_um=self.calib_window.z_step,
-                                             pad_z=self.calib_window.pad_z,
-                                             pixel_size_um=self.calib_window.ps,
-                                             n_obj_media=self.calib_window.n_media,
-                                             mode=self.calib_window.phase_dim,
-                                             use_gpu=self.calib_window.use_gpu,
-                                             gpu_id=self.calib_window.gpu_id)
+            logging.debug("Computing new reconstructor")
+
+            recon = initialize_reconstructor(
+                "PhaseFromBF",
+                image_dim=(stack.shape[-2], stack.shape[-1]),
+                wavelength_nm=int(
+                    self.calib_window.ui.le_recon_wavelength.text()
+                ),
+                NA_obj=self.calib_window.obj_na,
+                NA_illu=self.calib_window.cond_na,
+                mag=self.calib_window.mag,
+                n_slices=self.img_dim[-1],
+                z_step_um=self.calib_window.z_step,
+                pad_z=self.calib_window.pad_z,
+                pixel_size_um=self.calib_window.ps,
+                n_obj_media=self.calib_window.n_media,
+                mode=self.calib_window.phase_dim,
+                use_gpu=self.calib_window.use_gpu,
+                gpu_id=self.calib_window.gpu_id,
+            )
 
             # Emit reconstructor to be saved for later reconstructions
             self.phase_reconstructor_emitter.emit(recon)
@@ -214,65 +247,81 @@ def _reconstruct(self, stack):
 
             # compute new reconstructor if the old reconstructor properties have been modified
             if self._reconstructor_changed():
-                logging.debug('Reconstruction settings changed, updating reconstructor')
-
-                recon = initialize_reconstructor('PhaseFromBF',
-                                                 image_dim=(stack.shape[-2], stack.shape[-1]),
-                                                 wavelength_nm=int(self.calib_window.ui.le_recon_wavelength.text()),
-                                                 NA_obj=self.calib_window.obj_na,
-                                                 NA_illu=self.calib_window.cond_na,
-                                                 mag=self.calib_window.mag,
-                                                 n_slices=self.n_slices,
-                                                 z_step_um=self.calib_window.z_step,
-                                                 pad_z=self.calib_window.pad_z,
-                                                 pixel_size_um=self.calib_window.ps,
-                                                 n_obj_media=self.calib_window.n_media,
-                                                 mode=self.calib_window.phase_dim,
-                                                 use_gpu=self.calib_window.use_gpu,
-                                                 gpu_id=self.calib_window.gpu_id)
+                logging.debug(
+                    "Reconstruction settings changed, updating reconstructor"
+                )
+
+                recon = initialize_reconstructor(
+                    "PhaseFromBF",
+                    image_dim=(stack.shape[-2], stack.shape[-1]),
+                    wavelength_nm=int(
+                        self.calib_window.ui.le_recon_wavelength.text()
+                    ),
+                    NA_obj=self.calib_window.obj_na,
+                    NA_illu=self.calib_window.cond_na,
+                    mag=self.calib_window.mag,
+                    n_slices=self.n_slices,
+                    z_step_um=self.calib_window.z_step,
+                    pad_z=self.calib_window.pad_z,
+                    pixel_size_um=self.calib_window.ps,
+                    n_obj_media=self.calib_window.n_media,
+                    mode=self.calib_window.phase_dim,
+                    use_gpu=self.calib_window.use_gpu,
+                    gpu_id=self.calib_window.gpu_id,
+                )
 
                 # Emit reconstructor to be saved for later reconstructions
                 self.phase_reconstructor_emitter.emit(recon)
 
             # use previous reconstructor
             else:
-                logging.debug('Using previous reconstruction settings')
+                logging.debug("Using previous reconstruction settings")
                 recon = self.calib_window.phase_reconstructor
 
         # Begin reconstruction with stokes (needed for birefringence or phase)
-        logging.debug('Reconstructing...')
+        logging.debug("Reconstructing...")
         self._check_abort()
 
-        regularizer = 'Tikhonov' if self.calib_window.ui.cb_phase_denoiser.currentIndex() == 0 else 'TV'
+        regularizer = (
+            "Tikhonov"
+            if self.calib_window.ui.cb_phase_denoiser.currentIndex() == 0
+            else "TV"
+        )
         reg = float(self.calib_window.ui.le_phase_strength.text())
 
         # Perform deconvolution
-        if self.dim == '2D':
-
-            phase = reconstruct_phase2D(stack[0],
-                                        recon,
-                                        method=regularizer,
-                                        reg_p=reg,
-                                        itr=int(self.calib_window.ui.le_itr.text()),
-                                        rho=float(self.calib_window.ui.le_rho.text()))
+        if self.dim == "2D":
+
+            phase = reconstruct_phase2D(
+                stack[0],
+                recon,
+                method=regularizer,
+                reg_p=reg,
+                itr=int(self.calib_window.ui.le_itr.text()),
+                rho=float(self.calib_window.ui.le_rho.text()),
+            )
         else:
 
-            phase = reconstruct_phase3D(stack[0],
-                                        recon,
-                                        method=regularizer,
-                                        reg_re=reg,
-                                        itr=int(self.calib_window.ui.le_itr.text()),
-                                        rho=float(self.calib_window.ui.le_rho.text()))
+            phase = reconstruct_phase3D(
+                stack[0],
+                recon,
+                method=regularizer,
+                reg_re=reg,
+                itr=int(self.calib_window.ui.le_itr.text()),
+                rho=float(self.calib_window.ui.le_rho.text()),
+            )
 
         self._check_abort()
 
         # Update metadata in zarr attributes with reconstruction parameters
-        meta = extract_reconstruction_parameters(recon, magnification=self.calib_window.mag)
-        meta['regularization_method'] = regularizer
-        meta['regularization_strength'] = reg
-        if regularizer == 'TV':
-            meta['rho'] = float(self.calib_window.ui.le_rho.text())
-            meta['itr'] = int(self.calib_window.ui.le_itr.text())
+        meta = extract_reconstruction_parameters(
+            recon, magnification=self.calib_window.mag
+        )
+        meta["regularization_method"] = regularizer
+        meta["regularization_strength"] = reg
+        if regularizer == "TV":
+            meta["rho"] = float(self.calib_window.ui.le_rho.text())
+            meta["itr"] = int(self.calib_window.ui.le_itr.text())
 
         # return both variables, could contain images or could be null
         return phase, meta
@@ -295,29 +344,37 @@ def _save_imgs(self, phase, meta=None):
         # initialize
         chunk_size = (1, 1, 1, phase.shape[-2], phase.shape[-1])
         prefix = self.calib_window.save_name
-        name = f'PhaseSnap.zarr' if not prefix else f'{prefix}_PhaseSnap.zarr'
+        name = f"PhaseSnap.zarr" if not prefix else f"{prefix}_PhaseSnap.zarr"
 
         # create zarr root and position group
         writer.create_zarr_root(name)
 
         # Check if 2D
         if len(phase.shape) == 2:
-            writer.init_array(0, (1, 1, 1, phase.shape[-2], phase.shape[-1]), chunk_size, ['Phase2D'])
+            writer.init_array(
+                0,
+                (1, 1, 1, phase.shape[-2], phase.shape[-1]),
+                chunk_size,
+                ["Phase2D"],
+            )
             z = 0
 
         # Check if 3D
         else:
-            writer.init_array(0, (1, 1, phase.shape[-3], phase.shape[-2], phase.shape[-1]), chunk_size,
-                              ['Phase3D'])
+            writer.init_array(
+                0,
+                (1, 1, phase.shape[-3], phase.shape[-2], phase.shape[-1]),
+                chunk_size,
+                ["Phase3D"],
+            )
 
             z = slice(0, phase.shape[-3])
 
-
         # Write data to disk
         writer.write(phase, p=0, t=0, c=0, z=z)
 
         current_meta = writer.store.attrs.asdict()
-        current_meta['recOrder'] = meta
+        current_meta["recOrder"] = meta
         writer.store.attrs.put(current_meta)
 
     def _reconstructor_changed(self):
@@ -333,26 +390,30 @@ def _reconstructor_changed(self):
         changed = None
 
         # Attributes that are directly equivalent to worker attributes
-        attr_list = {'phase_dim': 'phase_deconv',
-                     'pad_z': 'pad_z',
-                     'n_media': 'n_media',
-                     'use_gpu': 'use_gpu',
-                     'gpu_id': 'gpu_id'
-                     }
+        attr_list = {
+            "phase_dim": "phase_deconv",
+            "pad_z": "pad_z",
+            "n_media": "n_media",
+            "use_gpu": "use_gpu",
+            "gpu_id": "gpu_id",
+        }
 
         # attributes that are modified upon passing them to reconstructor
-        attr_modified_list = {'obj_na': 'NA_obj',
-                              'cond_na': 'NA_illu',
-                              'wavelength': 'lambda_illu',
-                              'n_slices': 'N_defocus',
-                              'swing': 'chi',
-                              'ps': 'ps'
-                              }
+        attr_modified_list = {
+            "obj_na": "NA_obj",
+            "cond_na": "NA_illu",
+            "wavelength": "lambda_illu",
+            "n_slices": "N_defocus",
+            "swing": "chi",
+            "ps": "ps",
+        }
 
         self._check_abort()
         # check if equivalent attributes have diverged
         for key, value in attr_list.items():
-            if getattr(self.calib_window, key) != getattr(self.calib_window.phase_reconstructor, value):
+            if getattr(self.calib_window, key) != getattr(
+                self.calib_window.phase_reconstructor, value
+            ):
                 changed = True
                 break
             else:
@@ -361,29 +422,40 @@ def _reconstructor_changed(self):
         if not changed:
             # modify attributes to be equivalent and check for divergence
             for key, value in attr_modified_list.items():
-                if key == 'wavelength':
-                    if self.calib_window.wavelength * 1e-3 / self.calib_window.n_media != \
-                            self.calib_window.phase_reconstructor.lambda_illu:
+                if key == "wavelength":
+                    if (
+                        self.calib_window.wavelength
+                        * 1e-3
+                        / self.calib_window.n_media
+                        != self.calib_window.phase_reconstructor.lambda_illu
+                    ):
                         changed = True
                         break
                     else:
                         changed = False
-                elif key == 'n_slices':
-                    if getattr(self, key) != getattr(self.calib_window.phase_reconstructor, value):
+                elif key == "n_slices":
+                    if getattr(self, key) != getattr(
+                        self.calib_window.phase_reconstructor, value
+                    ):
                         changed = True
                         break
                     else:
                         changed = False
 
-                elif key == 'ps':
-                    if getattr(self.calib_window, key) / float(self.calib_window.mag) != getattr(self.calib_window.phase_reconstructor, value):
+                elif key == "ps":
+                    if getattr(self.calib_window, key) / float(
+                        self.calib_window.mag
+                    ) != getattr(self.calib_window.phase_reconstructor, value):
                         changed = True
                         break
                     else:
                         changed = False
                 else:
-                    if getattr(self.calib_window, key)/self.calib_window.n_media != \
-                            getattr(self.calib_window.phase_reconstructor, value):
+                    if getattr(
+                        self.calib_window, key
+                    ) / self.calib_window.n_media != getattr(
+                        self.calib_window.phase_reconstructor, value
+                    ):
                         changed = True
                     else:
                         changed = False
@@ -410,14 +482,27 @@ def _cleanup_acq(self):
                     closed = disp.isClosed()
                 dp.close()
 
-
                 # Try to delete the data, sometime it isn't cleaned up quickly enough and will
                 # return an error.  In this case, catch the error and then try to close again (seems to work).
                 try:
-                    save_prefix = self.calib_window.save_name if self.calib_window.save_name else None
-                    name = f'RawBFDataSnap.zarr' if not save_prefix else f'{save_prefix}_RawBFDataSnap.zarr'
+                    save_prefix = (
+                        self.calib_window.save_name
+                        if self.calib_window.save_name
+                        else None
+                    )
+                    name = (
+                        f"RawBFDataSnap.zarr"
+                        if not save_prefix
+                        else f"{save_prefix}_RawBFDataSnap.zarr"
+                    )
                     out_path = os.path.join(self.snap_dir, name)
-                    converter = ZarrConverter(os.path.join(dir_, prefix), out_path, 'ometiff', False, False)
+                    converter = ZarrConverter(
+                        os.path.join(dir_, prefix),
+                        out_path,
+                        "ometiff",
+                        False,
+                        False,
+                    )
                     converter.run_conversion()
                     shutil.rmtree(os.path.join(dir_, prefix))
                 except PermissionError as ex:
@@ -426,6 +511,7 @@ def _cleanup_acq(self):
             else:
                 continue
 
+
 # TODO: Cache common OTF's on local computers and use those for reconstruction
 class PolarizationAcquisitionWorker(WorkerBase):
     """
@@ -443,28 +529,45 @@ def __init__(self, calib_window, calib, mode):
         self.calib = calib
         self.mode = mode
         self.n_slices = None
-        self.prefix = 'recOrderPluginSnap'
+        self.prefix = "recOrderPluginSnap"
         self.dm = self.calib_window.mm.displays()
         self.channel_group = self.calib_window.config_group
 
         # Determine whether 2D or 3D acquisition is needed
-        if self.mode == 'birefringence' and self.calib_window.birefringence_dim == '2D':
-            self.dim = '2D'
+        if (
+            self.mode == "birefringence"
+            and self.calib_window.birefringence_dim == "2D"
+        ):
+            self.dim = "2D"
         else:
-            self.dim = '3D'
+            self.dim = "3D"
 
-        save_dir = self.calib_window.save_directory if self.calib_window.save_directory else self.calib_window.directory
+        save_dir = (
+            self.calib_window.save_directory
+            if self.calib_window.save_directory
+            else self.calib_window.directory
+        )
 
         if save_dir is None:
-            raise ValueError('save directory is empty, please specify a directory in the plugin')
+            raise ValueError(
+                "save directory is empty, please specify a directory in the plugin"
+            )
 
         # increment filename one more than last found saved snap
         i = 0
         prefix = self.calib_window.save_name
-        snap_dir = f'recOrderPluginSnap_{i}' if not prefix else f'{prefix}_recOrderPluginSnap_{i}'
+        snap_dir = (
+            f"recOrderPluginSnap_{i}"
+            if not prefix
+            else f"{prefix}_recOrderPluginSnap_{i}"
+        )
         while os.path.exists(os.path.join(save_dir, snap_dir)):
             i += 1
-            snap_dir = f'recOrderPluginSnap_{i}' if not prefix else f'{prefix}_recOrderPluginSnap_{i}'
+            snap_dir = (
+                f"recOrderPluginSnap_{i}"
+                if not prefix
+                else f"{prefix}_recOrderPluginSnap_{i}"
+            )
 
         self.snap_dir = os.path.join(save_dir, snap_dir)
         os.mkdir(self.snap_dir)
@@ -472,7 +575,7 @@ def __init__(self, calib_window, calib, mode):
     def _check_abort(self):
         if self.abort_requested:
             self.aborted.emit()
-            raise TimeoutError('Stop Requested')
+            raise TimeoutError("Stop Requested")
 
     def _check_ram(self):
         """
@@ -489,51 +592,55 @@ def work(self):
         Function that runs the 2D or 3D acquisition and reconstructs the data
         """
         self._check_ram()
-        logging.info('Running Acquisition...')
+        logging.info("Running Acquisition...")
 
         # List the Channels to acquire, if 5-state then append 5th channel
-        channels = ['State0', 'State1', 'State2', 'State3']
-        if self.calib_window.calib_scheme == '5-State':
-            channels.append('State4')
+        channels = ["State0", "State1", "State2", "State3"]
+        if self.calib_window.calib_scheme == "5-State":
+            channels.append("State4")
 
         self._check_abort()
 
         # Acquire 2D stack
-        if self.dim == '2D':
-            logging.debug('Acquiring 2D stack')
+        if self.dim == "2D":
+            logging.debug("Acquiring 2D stack")
 
             # Generate MDA Settings
-            self.settings = generate_acq_settings(self.calib_window.mm,
-                                             channel_group=self.channel_group,
-                                             channels=channels,
-                                             save_dir=self.snap_dir,
-                                             prefix=self.prefix,
-                                             keep_shutter_open_channels=True)
+            self.settings = generate_acq_settings(
+                self.calib_window.mm,
+                channel_group=self.channel_group,
+                channels=channels,
+                save_dir=self.snap_dir,
+                prefix=self.prefix,
+                keep_shutter_open_channels=True,
+            )
             self._check_abort()
             # acquire images
             stack = self._acquire()
 
         # Acquire 3D stack
         else:
-            logging.debug('Acquiring 3D stack')
+            logging.debug("Acquiring 3D stack")
 
             # Generate MDA Settings
-            self.settings = generate_acq_settings(self.calib_window.mm,
-                                             channel_group=self.channel_group,
-                                             channels=channels,
-                                             zstart=self.calib_window.z_start,
-                                             zend=self.calib_window.z_end,
-                                             zstep=self.calib_window.z_step,
-                                             save_dir=self.snap_dir,
-                                             prefix=self.prefix,
-                                             keep_shutter_open_channels=True,
-                                             keep_shutter_open_slices=True)
+            self.settings = generate_acq_settings(
+                self.calib_window.mm,
+                channel_group=self.channel_group,
+                channels=channels,
+                zstart=self.calib_window.z_start,
+                zend=self.calib_window.z_end,
+                zstep=self.calib_window.z_step,
+                save_dir=self.snap_dir,
+                prefix=self.prefix,
+                keep_shutter_open_channels=True,
+                keep_shutter_open_slices=True,
+            )
 
             self._check_abort()
 
             # set acquisition order to channel-first
-            self.settings['slicesFirst'] = False
-            self.settings['acqOrderMode'] = 0  # TIME_POS_SLICE_CHANNEL
+            self.settings["slicesFirst"] = False
+            self.settings["acqOrderMode"] = 0  # TIME_POS_SLICE_CHANNEL
 
             # acquire images
             stack = self._acquire()
@@ -548,13 +655,13 @@ def work(self):
         self._check_abort()
 
         # Save images
-        logging.debug('Saving Images')
+        logging.debug("Saving Images")
         self._save_imgs(birefringence, phase, meta)
 
         self._check_abort()
 
-        logging.info('Finished Acquisition')
-        logging.debug('Finished Acquisition')
+        logging.info("Finished Acquisition")
+        logging.debug("Finished Acquisition")
 
         # Emit the images and let thread know function is finished
         self.bire_image_emitter.emit(birefringence)
@@ -565,19 +672,21 @@ def _check_exposure(self) -> None:
         """
         Check that all LF channels have the same exposure settings. If not, abort Acquisition.
         """
-        logging.debug('Verifying exposure times...')
+        logging.debug("Verifying exposure times...")
         # parse exposure times
         channel_exposures = []
-        for channel in self.settings['channels']:
-            channel_exposures.append(channel['exposure'])
+        for channel in self.settings["channels"]:
+            channel_exposures.append(channel["exposure"])
 
         channel_exposures = np.array(channel_exposures)
         # check if exposure times are equal
         if not np.all(channel_exposures == channel_exposures[0]):
-            error_exposure_msg = f'The MDA exposure times are not equal! Aborting Acquisition.\n' \
-                                 f'Please manually set the exposure times to the same value from the MDA menu.'
+            error_exposure_msg = (
+                f"The MDA exposure times are not equal! Aborting Acquisition.\n"
+                f"Please manually set the exposure times to the same value from the MDA menu."
+            )
 
-            raise ValueError(error_exposure_msg)        
+            raise ValueError(error_exposure_msg)
 
         self._check_abort()
 
@@ -594,7 +703,9 @@ def _acquire(self) -> np.ndarray:
 
         # Acquire from MDA settings uses MM MDA GUI
         # Returns (1, 4/5, Z, Y, X) array
-        stack = acquire_from_settings(self.calib_window.mm, self.settings, grab_images=True)
+        stack = acquire_from_settings(
+            self.calib_window.mm, self.settings, grab_images=True
+        )
         self._check_abort()
 
         return stack
@@ -619,35 +730,38 @@ def _reconstruct(self, stack):
 
         self._check_abort()
 
-        wo_background_correction = rec_bkg_to_wo_bkg(self.calib_window.bg_option)
+        wo_background_correction = rec_bkg_to_wo_bkg(
+            self.calib_window.bg_option
+        )
 
         # Initialize the heavy reconstuctor
-        if self.mode == 'phase' or self.mode == 'all':
+        if self.mode == "phase" or self.mode == "all":
 
             self._check_abort()
 
             # if no reconstructor has been initialized before, create new reconstructor
             if not self.calib_window.phase_reconstructor:
-                logging.debug('Computing new reconstructor')
-
-
-                recon = initialize_reconstructor('QLIPP',
-                                                 image_dim=(stack.shape[-2], stack.shape[-1]),
-                                                 wavelength_nm=self.calib_window.wavelength,
-                                                 swing=self.calib_window.swing,
-                                                 calibration_scheme=self.calib_window.calib_scheme,
-                                                 NA_obj=self.calib_window.obj_na,
-                                                 NA_illu=self.calib_window.cond_na,
-                                                 mag=self.calib_window.mag,
-                                                 n_slices=self.n_slices,
-                                                 z_step_um=self.calib_window.z_step,
-                                                 pad_z=self.calib_window.pad_z,
-                                                 pixel_size_um=self.calib_window.ps,
-                                                 bg_correction=wo_background_correction,
-                                                 n_obj_media=self.calib_window.n_media,
-                                                 mode=self.calib_window.phase_dim,
-                                                 use_gpu=self.calib_window.use_gpu,
-                                                 gpu_id=self.calib_window.gpu_id)
+                logging.debug("Computing new reconstructor")
+
+                recon = initialize_reconstructor(
+                    "QLIPP",
+                    image_dim=(stack.shape[-2], stack.shape[-1]),
+                    wavelength_nm=self.calib_window.wavelength,
+                    swing=self.calib_window.swing,
+                    calibration_scheme=self.calib_window.calib_scheme,
+                    NA_obj=self.calib_window.obj_na,
+                    NA_illu=self.calib_window.cond_na,
+                    mag=self.calib_window.mag,
+                    n_slices=self.n_slices,
+                    z_step_um=self.calib_window.z_step,
+                    pad_z=self.calib_window.pad_z,
+                    pixel_size_um=self.calib_window.ps,
+                    bg_correction=wo_background_correction,
+                    n_obj_media=self.calib_window.n_media,
+                    mode=self.calib_window.phase_dim,
+                    use_gpu=self.calib_window.use_gpu,
+                    gpu_id=self.calib_window.gpu_id,
+                )
 
                 # Emit reconstructor to be saved for later reconstructions
                 self.phase_reconstructor_emitter.emit(recon)
@@ -658,66 +772,78 @@ def _reconstruct(self, stack):
 
                 # compute new reconstructor if the old reconstructor properties have been modified
                 if self._reconstructor_changed():
-                    logging.debug('Reconstruction settings changed, updating reconstructor')
-
-                    recon = initialize_reconstructor('QLIPP',
-                                                     image_dim=(stack.shape[-2], stack.shape[-1]),
-                                                     wavelength_nm=self.calib_window.wavelength,
-                                                     swing=self.calib_window.swing,
-                                                     calibration_scheme=self.calib_window.calib_scheme,
-                                                     NA_obj=self.calib_window.obj_na,
-                                                     NA_illu=self.calib_window.cond_na,
-                                                     mag=self.calib_window.mag,
-                                                     n_slices=self.n_slices,
-                                                     z_step_um=self.calib_window.z_step,
-                                                     pad_z=self.calib_window.pad_z,
-                                                     pixel_size_um=self.calib_window.ps,
-                                                     bg_correction=wo_background_correction,
-                                                     n_obj_media=self.calib_window.n_media,
-                                                     mode=self.calib_window.phase_dim,
-                                                     use_gpu=self.calib_window.use_gpu,
-                                                     gpu_id=self.calib_window.gpu_id)
+                    logging.debug(
+                        "Reconstruction settings changed, updating reconstructor"
+                    )
+
+                    recon = initialize_reconstructor(
+                        "QLIPP",
+                        image_dim=(stack.shape[-2], stack.shape[-1]),
+                        wavelength_nm=self.calib_window.wavelength,
+                        swing=self.calib_window.swing,
+                        calibration_scheme=self.calib_window.calib_scheme,
+                        NA_obj=self.calib_window.obj_na,
+                        NA_illu=self.calib_window.cond_na,
+                        mag=self.calib_window.mag,
+                        n_slices=self.n_slices,
+                        z_step_um=self.calib_window.z_step,
+                        pad_z=self.calib_window.pad_z,
+                        pixel_size_um=self.calib_window.ps,
+                        bg_correction=wo_background_correction,
+                        n_obj_media=self.calib_window.n_media,
+                        mode=self.calib_window.phase_dim,
+                        use_gpu=self.calib_window.use_gpu,
+                        gpu_id=self.calib_window.gpu_id,
+                    )
 
                     self.phase_reconstructor_emitter.emit(recon)
 
                 # use previous reconstructor
                 else:
-                    logging.debug('Using previous reconstruction settings')
+                    logging.debug("Using previous reconstruction settings")
                     recon = self.calib_window.phase_reconstructor
 
         # if phase isn't desired, initialize the lighter birefringence only reconstructor
         # no need to save this reconstructor for later as it is pretty quick to compute
         else:
             self._check_abort()
-            logging.debug('Creating birefringence only reconstructor')
-            recon = initialize_reconstructor('birefringence',
-                                             image_dim=(stack.shape[-2], stack.shape[-1]),
-                                             calibration_scheme=self.calib_window.calib_scheme,
-                                             wavelength_nm=self.calib_window.wavelength,
-                                             swing=self.calib_window.swing,
-                                             bg_correction=wo_background_correction,
-                                             n_slices=self.n_slices)
+            logging.debug("Creating birefringence only reconstructor")
+            recon = initialize_reconstructor(
+                "birefringence",
+                image_dim=(stack.shape[-2], stack.shape[-1]),
+                calibration_scheme=self.calib_window.calib_scheme,
+                wavelength_nm=self.calib_window.wavelength,
+                swing=self.calib_window.swing,
+                bg_correction=wo_background_correction,
+                n_slices=self.n_slices,
+            )
 
         # Prepare background corrections for waveorder
         # This block mimics qlipp_pipeline.py L110-119.
-        if self.calib_window.bg_option in ['global', 'local_fit+']:
-            logging.debug('Loading BG Data')
+        if self.calib_window.bg_option in ["global", "local_fit+"]:
+            logging.debug("Loading BG Data")
             self._check_abort()
-            bg_data = self._load_bg(self.calib_window.acq_bg_directory, stack.shape[-2], stack.shape[-1])
+            bg_data = self._load_bg(
+                self.calib_window.acq_bg_directory,
+                stack.shape[-2],
+                stack.shape[-1],
+            )
             self._check_abort()
             bg_stokes = recon.Stokes_recon(bg_data)
             self._check_abort()
             bg_stokes = recon.Stokes_transform(bg_stokes)
             self._check_abort()
-        elif self.calib_window.bg_option == 'local_fit':
+        elif self.calib_window.bg_option == "local_fit":
             bg_stokes = np.zeros((5, stack.shape[-2], stack.shape[-1]))
-            bg_stokes[0, ...] = 1  # Set background to "identity" Stokes parameters.
+            bg_stokes[
+                0, ...
+            ] = 1  # Set background to "identity" Stokes parameters.
         else:
-            logging.debug('No Background Correction method chosen')
+            logging.debug("No Background Correction method chosen")
             bg_stokes = None
 
         # Begin reconstruction with stokes (needed for birefringence or phase)
-        logging.debug('Reconstructing...')
+        logging.debug("Reconstructing...")
         self._check_abort()
         stokes = reconstruct_qlipp_stokes(stack, recon, bg_stokes)
         self._check_abort()
@@ -726,68 +852,86 @@ def _reconstruct(self, stack):
         birefringence = None
         phase = None
 
-        regularizer = 'Tikhonov' if self.calib_window.ui.cb_phase_denoiser.currentIndex() == 0 else 'TV'
+        regularizer = (
+            "Tikhonov"
+            if self.calib_window.ui.cb_phase_denoiser.currentIndex() == 0
+            else "TV"
+        )
         reg = float(self.calib_window.ui.le_phase_strength.text())
 
         # reconstruct both phase and birefringence
-        if self.mode == 'all':
-            if self.calib_window.birefringence_dim == '2D':
-                birefringence = reconstruct_qlipp_birefringence(stokes[:, stokes.shape[1]//2, :, :], recon)
+        if self.mode == "all":
+            if self.calib_window.birefringence_dim == "2D":
+                birefringence = reconstruct_qlipp_birefringence(
+                    stokes[:, stokes.shape[1] // 2, :, :], recon
+                )
             else:
                 birefringence = reconstruct_qlipp_birefringence(stokes, recon)
-            birefringence[0] = birefringence[0] / (2 * np.pi) * self.calib_window.wavelength
+            birefringence[0] = (
+                birefringence[0] / (2 * np.pi) * self.calib_window.wavelength
+            )
             self._check_abort()
 
-            if self.calib_window.phase_dim == '2D':
-                phase = reconstruct_phase2D(stokes[0],
-                                            recon,
-                                            method=regularizer,
-                                            reg_p=reg,
-                                            itr=int(self.calib_window.ui.le_itr.text()),
-                                            rho=float(self.calib_window.ui.le_rho.text()))
+            if self.calib_window.phase_dim == "2D":
+                phase = reconstruct_phase2D(
+                    stokes[0],
+                    recon,
+                    method=regularizer,
+                    reg_p=reg,
+                    itr=int(self.calib_window.ui.le_itr.text()),
+                    rho=float(self.calib_window.ui.le_rho.text()),
+                )
             else:
-                phase = reconstruct_phase3D(stokes[0],
-                                            recon,
-                                            method=regularizer,
-                                            reg_re=reg,
-                                            itr=int(self.calib_window.ui.le_itr.text()),
-                                            rho=float(self.calib_window.ui.le_rho.text()))
+                phase = reconstruct_phase3D(
+                    stokes[0],
+                    recon,
+                    method=regularizer,
+                    reg_re=reg,
+                    itr=int(self.calib_window.ui.le_itr.text()),
+                    rho=float(self.calib_window.ui.le_rho.text()),
+                )
 
             self._check_abort()
 
         # reconstruct phase only
-        elif self.mode == 'phase':
-            if self.calib_window.phase_dim == '2D':
-                phase = reconstruct_phase2D(stokes[0],
-                                            recon,
-                                            method=regularizer,
-                                            reg_p=reg,
-                                            itr=int(self.calib_window.ui.le_itr.text()),
-                                            rho=float(self.calib_window.ui.le_rho.text()))
+        elif self.mode == "phase":
+            if self.calib_window.phase_dim == "2D":
+                phase = reconstruct_phase2D(
+                    stokes[0],
+                    recon,
+                    method=regularizer,
+                    reg_p=reg,
+                    itr=int(self.calib_window.ui.le_itr.text()),
+                    rho=float(self.calib_window.ui.le_rho.text()),
+                )
             else:
-                phase = reconstruct_phase3D(stokes[0],
-                                            recon,
-                                            method=regularizer,
-                                            reg_re=reg,
-                                            itr=int(self.calib_window.ui.le_itr.text()),
-                                            rho=float(self.calib_window.ui.le_rho.text()))
+                phase = reconstruct_phase3D(
+                    stokes[0],
+                    recon,
+                    method=regularizer,
+                    reg_re=reg,
+                    itr=int(self.calib_window.ui.le_itr.text()),
+                    rho=float(self.calib_window.ui.le_rho.text()),
+                )
             self._check_abort()
 
         # reconstruct birefringence only
-        elif self.mode == 'birefringence':
+        elif self.mode == "birefringence":
             birefringence = reconstruct_qlipp_birefringence(stokes, recon)
-            birefringence[0] = birefringence[0] / (2 * np.pi) * self.calib_window.wavelength
+            birefringence[0] = (
+                birefringence[0] / (2 * np.pi) * self.calib_window.wavelength
+            )
             self._check_abort()
 
         else:
-            raise ValueError('Reconstruction Mode Not Understood')
+            raise ValueError("Reconstruction Mode Not Understood")
 
         meta = extract_reconstruction_parameters(recon, self.calib_window.mag)
-        meta['regularization_method'] = regularizer
-        meta['regularization_strength'] = reg
-        if regularizer == 'TV':
-            meta['rho'] = float(self.calib_window.ui.le_rho.text())
-            meta['itr'] = int(self.calib_window.ui.le_itr.text())
+        meta["regularization_method"] = regularizer
+        meta["regularization_strength"] = reg
+        if regularizer == "TV":
+            meta["rho"] = float(self.calib_window.ui.le_rho.text())
+            meta["itr"] = int(self.calib_window.ui.le_itr.text())
 
         # return both variables, could contain images or could be null
         return birefringence, phase, meta
@@ -811,32 +955,62 @@ def _save_imgs(self, birefringence, phase, meta=None):
         if birefringence is not None:
 
             # initialize
-            chunk_size = (1, 1, 1, birefringence.shape[-2],birefringence.shape[-1])
+            chunk_size = (
+                1,
+                1,
+                1,
+                birefringence.shape[-2],
+                birefringence.shape[-1],
+            )
 
             # increment filename one more than last found saved snap
             prefix = self.calib_window.save_name
-            name = f'BirefringenceSnap.zarr' if not prefix else f'{prefix}_BirefringenceSnap.zarr'
+            name = (
+                f"BirefringenceSnap.zarr"
+                if not prefix
+                else f"{prefix}_BirefringenceSnap.zarr"
+            )
 
             # create zarr root and position group
             writer.create_zarr_root(name)
 
             # Check if 2D
             if len(birefringence.shape) == 3:
-                writer.init_array(0, (1, 4, 1, birefringence.shape[-2], birefringence.shape[-1]),
-                                  chunk_size, ['Retardance', 'Orientation', 'BF', 'Pol'])
+                writer.init_array(
+                    0,
+                    (
+                        1,
+                        4,
+                        1,
+                        birefringence.shape[-2],
+                        birefringence.shape[-1],
+                    ),
+                    chunk_size,
+                    ["Retardance", "Orientation", "BF", "Pol"],
+                )
                 z = 0
 
             # Check if 3D
             else:
-                writer.init_array(0, (1, 4, birefringence.shape[-3], birefringence.shape[-2], birefringence.shape[-1]),
-                                  chunk_size, ['Retardance', 'Orientation', 'BF', 'Pol'])
+                writer.init_array(
+                    0,
+                    (
+                        1,
+                        4,
+                        birefringence.shape[-3],
+                        birefringence.shape[-2],
+                        birefringence.shape[-1],
+                    ),
+                    chunk_size,
+                    ["Retardance", "Orientation", "BF", "Pol"],
+                )
                 z = slice(0, birefringence.shape[-3])
 
             # Write the data to disk
             writer.write(birefringence, p=0, t=0, c=slice(0, 4), z=z)
 
             current_meta = writer.store.attrs.asdict()
-            current_meta['recOrder'] = meta
+            current_meta["recOrder"] = meta
             writer.store.attrs.put(current_meta)
 
         if phase is not None:
@@ -846,26 +1020,38 @@ def _save_imgs(self, birefringence, phase, meta=None):
 
             # increment filename one more than last found saved snap
             prefix = self.calib_window.save_name
-            name = f'PhaseSnap.zarr' if not prefix else f'{prefix}_PhaseSnap.zarr'
+            name = (
+                f"PhaseSnap.zarr" if not prefix else f"{prefix}_PhaseSnap.zarr"
+            )
 
             # create zarr root and position group
             writer.create_zarr_root(name)
 
             # Check if 2D
             if len(phase.shape) == 2:
-                writer.init_array(0, (1, 1, 1, phase.shape[-2], phase.shape[-1]), chunk_size, ['Phase2D'])
+                writer.init_array(
+                    0,
+                    (1, 1, 1, phase.shape[-2], phase.shape[-1]),
+                    chunk_size,
+                    ["Phase2D"],
+                )
                 z = 0
 
             # Check if 3D
             else:
-                writer.init_array(0, (1, 1, phase.shape[-3], phase.shape[-2], phase.shape[-1]), chunk_size, ['Phase3D'])
+                writer.init_array(
+                    0,
+                    (1, 1, phase.shape[-3], phase.shape[-2], phase.shape[-1]),
+                    chunk_size,
+                    ["Phase3D"],
+                )
                 z = slice(0, phase.shape[-3])
 
             # Write data to disk
             writer.write(phase, p=0, t=0, c=0, z=z)
 
             current_meta = writer.store.attrs.asdict()
-            current_meta['recOrder'] = meta
+            current_meta["recOrder"] = meta
             writer.store.attrs.put(current_meta)
 
     def _load_bg(self, path, height, width):
@@ -885,7 +1071,7 @@ def _load_bg(self, path, height, width):
 
         """
 
-        #TODO: Change to just accept ROI
+        # TODO: Change to just accept ROI
         try:
             metadata_path = get_last_metadata_file(path)
             metadata = MetadataReader(metadata_path)
@@ -910,27 +1096,31 @@ def _reconstructor_changed(self):
         changed = None
 
         # Attributes that are directly equivalent to worker attributes
-        attr_list = {'phase_dim': 'phase_deconv',
-                     'pad_z': 'pad_z',
-                     'n_media': 'n_media',
-                     'bg_option': 'bg_option',
-                     'use_gpu': 'use_gpu',
-                     'gpu_id': 'gpu_id'
-                     }
+        attr_list = {
+            "phase_dim": "phase_deconv",
+            "pad_z": "pad_z",
+            "n_media": "n_media",
+            "bg_option": "bg_option",
+            "use_gpu": "use_gpu",
+            "gpu_id": "gpu_id",
+        }
 
         # attributes that are modified upon passing them to reconstructor
-        attr_modified_list = {'obj_na': 'NA_obj',
-                              'cond_na': 'NA_illu',
-                              'wavelength': 'lambda_illu',
-                              'n_slices': 'N_defocus',
-                              'swing': 'chi',
-                              'ps': 'ps'
-                              }
+        attr_modified_list = {
+            "obj_na": "NA_obj",
+            "cond_na": "NA_illu",
+            "wavelength": "lambda_illu",
+            "n_slices": "N_defocus",
+            "swing": "chi",
+            "ps": "ps",
+        }
 
         self._check_abort()
         # check if equivalent attributes have diverged
         for key, value in attr_list.items():
-            if getattr(self.calib_window, key) != getattr(self.calib_window.phase_reconstructor, value):
+            if getattr(self.calib_window, key) != getattr(
+                self.calib_window.phase_reconstructor, value
+            ):
                 changed = True
                 break
             else:
@@ -939,41 +1129,58 @@ def _reconstructor_changed(self):
         if not changed:
             # modify attributes to be equivalent and check for divergence
             for key, value in attr_modified_list.items():
-                if key == 'swing':
-                    if self.calib_window.calib_scheme == '5-State':
-                        if self.calib_window.swing * 2 * np.pi != self.calib_window.phase_reconstructor.chi:
+                if key == "swing":
+                    if self.calib_window.calib_scheme == "5-State":
+                        if (
+                            self.calib_window.swing * 2 * np.pi
+                            != self.calib_window.phase_reconstructor.chi
+                        ):
                             changed = True
                         else:
                             changed = False
                     else:
-                        if self.calib_window.swing != self.calib_window.phase_reconstructor.chi:
+                        if (
+                            self.calib_window.swing
+                            != self.calib_window.phase_reconstructor.chi
+                        ):
                             changed = True
                         else:
                             changed = False
 
-                elif key == 'wavelength':
-                    if self.calib_window.wavelength * 1e-3 / self.calib_window.n_media != \
-                            self.calib_window.phase_reconstructor.lambda_illu:
+                elif key == "wavelength":
+                    if (
+                        self.calib_window.wavelength
+                        * 1e-3
+                        / self.calib_window.n_media
+                        != self.calib_window.phase_reconstructor.lambda_illu
+                    ):
                         changed = True
                         break
                     else:
                         changed = False
-                elif key == 'n_slices':
-                    if getattr(self, key) != getattr(self.calib_window.phase_reconstructor, value):
+                elif key == "n_slices":
+                    if getattr(self, key) != getattr(
+                        self.calib_window.phase_reconstructor, value
+                    ):
                         changed = True
                         break
                     else:
                         changed = False
 
-                elif key == 'ps':
-                    if getattr(self.calib_window, key) / float(self.calib_window.mag) != getattr(self.calib_window.phase_reconstructor, value):
+                elif key == "ps":
+                    if getattr(self.calib_window, key) / float(
+                        self.calib_window.mag
+                    ) != getattr(self.calib_window.phase_reconstructor, value):
                         changed = True
                         break
                     else:
                         changed = False
                 else:
-                    if getattr(self.calib_window, key)/self.calib_window.n_media != \
-                            getattr(self.calib_window.phase_reconstructor, value):
+                    if getattr(
+                        self.calib_window, key
+                    ) / self.calib_window.n_media != getattr(
+                        self.calib_window.phase_reconstructor, value
+                    ):
                         changed = True
                     else:
                         changed = False
@@ -1000,14 +1207,27 @@ def _cleanup_acq(self):
                     closed = disp.isClosed()
                 dp.close()
 
-
                 # Try to delete the data, sometime it isn't cleaned up quickly enough and will
                 # return an error.  In this case, catch the error and then try to close again (seems to work).
                 try:
-                    save_prefix = self.calib_window.save_name if self.calib_window.save_name else None
-                    name = f'RawPolDataSnap.zarr' if not save_prefix else f'{save_prefix}_RawPolDataSnap.zarr'
+                    save_prefix = (
+                        self.calib_window.save_name
+                        if self.calib_window.save_name
+                        else None
+                    )
+                    name = (
+                        f"RawPolDataSnap.zarr"
+                        if not save_prefix
+                        else f"{save_prefix}_RawPolDataSnap.zarr"
+                    )
                     out_path = os.path.join(self.snap_dir, name)
-                    converter = ZarrConverter(os.path.join(dir_, prefix), out_path, 'ometiff', False, False)
+                    converter = ZarrConverter(
+                        os.path.join(dir_, prefix),
+                        out_path,
+                        "ometiff",
+                        False,
+                        False,
+                    )
                     converter.run_conversion()
                     shutil.rmtree(os.path.join(dir_, prefix))
                 except PermissionError as ex:
@@ -1046,7 +1266,7 @@ def __init__(self, calib_window, bg_data):
     def _check_abort(self):
         if self.abort_requested:
             self.aborted.emit()
-            raise TimeoutError('Stop Requested')
+            raise TimeoutError("Stop Requested")
 
     def get_byte_offset(self, offsets, page):
         """
@@ -1073,7 +1293,9 @@ def get_byte_offset(self, offsets, page):
 
         return array_offset
 
-    def listen_for_images(self, array, file, offsets, interval, dim3, dim2, dim1, dim0, dim_order):
+    def listen_for_images(
+        self, array, file, offsets, interval, dim3, dim2, dim1, dim0, dim_order
+    ):
         """
 
         Parameters
@@ -1101,16 +1323,36 @@ def listen_for_images(self, array, file, offsets, interval, dim3, dim2, dim1, di
 
         # Order dimensions that we will loop through in order to match the acquisition
         if dim_order == 0:
-            dims = [[dim3, self.n_frames], [dim2, self.n_pos], [dim1, self.n_slices], [dim0, self.n_channels]]
+            dims = [
+                [dim3, self.n_frames],
+                [dim2, self.n_pos],
+                [dim1, self.n_slices],
+                [dim0, self.n_channels],
+            ]
             channel_dim = 0
         elif dim_order == 1:
-            dims = [[dim3, self.n_frames], [dim2, self.n_pos], [dim1, self.n_channels], [dim0, self.n_slices]]
+            dims = [
+                [dim3, self.n_frames],
+                [dim2, self.n_pos],
+                [dim1, self.n_channels],
+                [dim0, self.n_slices],
+            ]
             channel_dim = 1
         elif dim_order == 2:
-            dims = [[dim3, self.n_pos], [dim2, self.n_frames], [dim1, self.n_slices], [dim0, self.n_channels]]
+            dims = [
+                [dim3, self.n_pos],
+                [dim2, self.n_frames],
+                [dim1, self.n_slices],
+                [dim0, self.n_channels],
+            ]
             channel_dim = 0
         else:
-            dims = [[dim3, self.n_pos], [dim2, self.n_frames], [dim1, self.n_channels], [dim0, self.n_slices]]
+            dims = [
+                [dim3, self.n_pos],
+                [dim2, self.n_frames],
+                [dim1, self.n_channels],
+                [dim0, self.n_slices],
+            ]
             channel_dim = 1
 
         # Loop through dimensions in the order they are acquired
@@ -1134,13 +1376,20 @@ def listen_for_images(self, array, file, offsets, interval, dim3, dim2, dim1, di
                                 self._check_abort()
                                 tf = tiff.TiffFile(file)
                                 time.sleep(interval)
-                                offsets = tf.micromanager_metadata['IndexMap']['Offset']
+                                offsets = tf.micromanager_metadata["IndexMap"][
+                                    "Offset"
+                                ]
                                 tf.close()
                                 offset = self.get_byte_offset(offsets, idx)
                         else:
                             offset = self.get_byte_offset(offsets, idx)
 
-                        if idx < (self.n_slices * self.n_channels * self.n_frames * self.n_pos):
+                        if idx < (
+                            self.n_slices
+                            * self.n_channels
+                            * self.n_frames
+                            * self.n_pos
+                        ):
 
                             # Assign dimensions based off acquisition order to correctly add image to array
                             if dim_order == 0:
@@ -1155,11 +1404,20 @@ def listen_for_images(self, array, file, offsets, interval, dim3, dim2, dim1, di
                             self._check_abort()
 
                             # Add Image to array
-                            img = np.memmap(file, dtype=self.dtype, mode='r', offset=offset, shape=self.shape)
+                            img = np.memmap(
+                                file,
+                                dtype=self.dtype,
+                                mode="r",
+                                offset=offset,
+                                shape=self.shape,
+                            )
                             array[c, z] = img
 
                             # If Channel first, compute birefringence here
-                            if channel_dim == 0 and dim0 == self.n_channels - 1:
+                            if (
+                                channel_dim == 0
+                                and dim0 == self.n_channels - 1
+                            ):
                                 self._check_abort()
 
                                 # Compute birefringence
@@ -1168,7 +1426,12 @@ def listen_for_images(self, array, file, offsets, interval, dim3, dim2, dim1, di
                             idx += 1
 
                     # Reset Range to 0 to account for starting this function in middle of a dimension
-                    if idx < (self.n_slices * self.n_channels * self.n_frames * self.n_pos):
+                    if idx < (
+                        self.n_slices
+                        * self.n_channels
+                        * self.n_frames
+                        * self.n_pos
+                    ):
                         dims[2][0] = 0
                         dims[3][0] = 0
 
@@ -1191,7 +1454,12 @@ def listen_for_images(self, array, file, offsets, interval, dim3, dim2, dim1, di
                         continue
 
                 # Reset range to 0 to account for starting this function in the middle of a dimension
-                if idx < (self.n_slices * self.n_channels * self.n_frames * self.n_pos):
+                if idx < (
+                    self.n_slices
+                    * self.n_channels
+                    * self.n_frames
+                    * self.n_pos
+                ):
                     dims[1][0] = 0
 
         # Return at the end of the acquisition
@@ -1206,31 +1474,37 @@ def compute_and_save(self, array, p, t, z):
 
         # If the napari layer doesn't exist yet, create the zarr store to emit to napari
         if self.prefix not in self.calib_window.viewer.layers:
-            self.store = zarr.open(os.path.join(self.root, self.prefix+'.zarr'))
-            self.store.zeros(name='Birefringence',
-                             shape=(self.n_pos,
-                                    self.n_frames,
-                                    2,
-                                    self.n_slices,
-                                    self.shape[0],
-                                    self.shape[1]),
-                             chunks=(1, 1, 1, 1, self.shape[0], self.shape[1]),
-                             overwrite=True)
+            self.store = zarr.open(
+                os.path.join(self.root, self.prefix + ".zarr")
+            )
+            self.store.zeros(
+                name="Birefringence",
+                shape=(
+                    self.n_pos,
+                    self.n_frames,
+                    2,
+                    self.n_slices,
+                    self.shape[0],
+                    self.shape[1],
+                ),
+                chunks=(1, 1, 1, 1, self.shape[0], self.shape[1]),
+                overwrite=True,
+            )
 
             # Add data and send out the store.  Once the store has been emitted, we can add data to the store
             # without needing to emit the store again (thanks to napari's handling of zarr datasets)
             if len(birefringence.shape) == 4:
-                self.store['Birefringence'][p, t] = birefringence
+                self.store["Birefringence"][p, t] = birefringence
             else:
-                self.store['Birefringence'][p, t, :, z] = birefringence
+                self.store["Birefringence"][p, t, :, z] = birefringence
 
             self.store_emitter.emit(self.store)
 
         else:
             if len(birefringence.shape) == 4:
-                self.store['Birefringence'][p, t] = birefringence
+                self.store["Birefringence"][p, t] = birefringence
             else:
-                self.store['Birefringence'][p, t, :, z] = birefringence
+                self.store["Birefringence"][p, t, :, z] = birefringence
 
         # Emit the current dimensions so that we can update the napari dimension slider
         self.dim_emitter.emit((p, t, z))
@@ -1247,68 +1521,97 @@ def work(self):
         s = acq_man.getAcquisitionSettings()
         self.root = s.root()
         self.prefix = s.prefix()
-        self.n_frames, self.interval = (s.numFrames(), s.intervalMs() / 1000) if s.useFrames() else (1, 1)
+        self.n_frames, self.interval = (
+            (s.numFrames(), s.intervalMs() / 1000) if s.useFrames() else (1, 1)
+        )
         self.n_channels = s.channels().size() if s.useChannels() else 1
         self.n_slices = s.slices().size() if s.useChannels() else 1
-        self.n_pos = 1 if not s.usePositionList() else \
-            self.calib_window.mm.getPositionListManager().getPositionList().getNumberOfPositions()
+        self.n_pos = (
+            1
+            if not s.usePositionList()
+            else self.calib_window.mm.getPositionListManager()
+            .getPositionList()
+            .getNumberOfPositions()
+        )
         dim_order = s.acqOrderMode()
 
         # Get File Path corresponding to current dataset
         path = os.path.join(self.root, self.prefix)
-        files = [fn for fn in glob.glob(path + '*') if '.zarr' not in fn]
-        index = max([int(x.strip(path + '_')) for x in files])
+        files = [fn for fn in glob.glob(path + "*") if ".zarr" not in fn]
+        index = max([int(x.strip(path + "_")) for x in files])
 
-        self.prefix = self.prefix + f'_{index}'
+        self.prefix = self.prefix + f"_{index}"
         full_path = os.path.join(self.root, self.prefix)
-        first_file_path = os.path.join(full_path, self.prefix + '_MMStack.ome.tif')
+        first_file_path = os.path.join(
+            full_path, self.prefix + "_MMStack.ome.tif"
+        )
 
         file = tiff.TiffFile(first_file_path)
         file_path = first_file_path
-        self.shape = (file.micromanager_metadata['Summary']['Height'], file.micromanager_metadata['Summary']['Width'])
+        self.shape = (
+            file.micromanager_metadata["Summary"]["Height"],
+            file.micromanager_metadata["Summary"]["Width"],
+        )
         self.dtype = file.pages[0].dtype
-        offsets = file.micromanager_metadata['IndexMap']['Offset']
+        offsets = file.micromanager_metadata["IndexMap"]["Offset"]
         file.close()
 
         self._check_abort()
 
         # Init Reconstruction Class
-        self.reconstructor = QLIPPBirefringenceCompute(self.shape,
-                                                       self.calib_window.calib_scheme,
-                                                       self.calib_window.wavelength,
-                                                       self.calib_window.swing,
-                                                       self.n_slices,
-                                                       self.calib_window.bg_option,
-                                                       self.bg_data)
+        self.reconstructor = QLIPPBirefringenceCompute(
+            self.shape,
+            self.calib_window.calib_scheme,
+            self.calib_window.wavelength,
+            self.calib_window.swing,
+            self.n_slices,
+            self.calib_window.bg_option,
+            self.bg_data,
+        )
 
         self._check_abort()
 
         # initialize dimensions / array for the loop
         idx, dim3, dim2, dim1, dim0 = 0, 0, 0, 0, 0
-        array = np.zeros((self.n_channels, self.n_slices, self.shape[0], self.shape[1]))
+        array = np.zeros(
+            (self.n_channels, self.n_slices, self.shape[0], self.shape[1])
+        )
         file_count = 0
         total_idx = 0
 
         # Run until the function has collected the totality of the data
-        while total_idx < (self.n_slices * self.n_channels * self.n_frames * self.n_pos):
+        while total_idx < (
+            self.n_slices * self.n_channels * self.n_frames * self.n_pos
+        ):
 
             self._check_abort()
 
             # this will loop through reading images in a single file as it's being written
             # when it has successfully loaded all of the images from the file, it'll move on to the next
-            array, idx, dim3, dim2, dim1, dim0 = self.listen_for_images(array,
-                                                            file_path,
-                                                            offsets,
-                                                            self.interval,
-                                                            dim3, dim2, dim1, dim0, dim_order)
+            array, idx, dim3, dim2, dim1, dim0 = self.listen_for_images(
+                array,
+                file_path,
+                offsets,
+                self.interval,
+                dim3,
+                dim2,
+                dim1,
+                dim0,
+                dim_order,
+            )
 
             total_idx += idx
 
             # If acquisition is not finished, grab the next file and listen for images
-            if total_idx != self.n_slices * self.n_channels * self.n_frames * self.n_pos:
+            if (
+                total_idx
+                != self.n_slices * self.n_channels * self.n_frames * self.n_pos
+            ):
                 time.sleep(1)
                 file_count += 1
-                file_path = os.path.join(full_path, self.prefix + f'_MMStack_{file_count}.ome.tif')
+                file_path = os.path.join(
+                    full_path, self.prefix + f"_MMStack_{file_count}.ome.tif"
+                )
                 file = tiff.TiffFile(file_path)
-                offsets = file.micromanager_metadata['IndexMap']['Offset']
+                offsets = file.micromanager_metadata["IndexMap"]["Offset"]
                 file.close()
diff --git a/recOrder/plugin/workers/calibration_workers.py b/recOrder/plugin/workers/calibration_workers.py
index 24911a47..6183729a 100644
--- a/recOrder/plugin/workers/calibration_workers.py
+++ b/recOrder/plugin/workers/calibration_workers.py
@@ -3,8 +3,11 @@
 
 from qtpy.QtCore import Signal
 from napari.qt.threading import WorkerBaseSignals, WorkerBase, thread_worker
-from recOrder.compute.qlipp_compute import initialize_reconstructor, \
-    reconstruct_qlipp_birefringence, reconstruct_qlipp_stokes
+from recOrder.compute.qlipp_compute import (
+    initialize_reconstructor,
+    reconstruct_qlipp_birefringence,
+    reconstruct_qlipp_stokes,
+)
 from recOrder.io.core_functions import set_lc_state, snap_and_average
 from recOrder.io.utils import MockEmitter
 from recOrder.calib.Calibration import LC_DEVICE_NAME
@@ -19,6 +22,7 @@
 
 # type hint/check
 from typing import TYPE_CHECKING
+
 # avoid runtime import error
 if TYPE_CHECKING:
     from _typeshed import StrOrBytesPath
@@ -68,7 +72,7 @@ def __init_subclass__(cls, signals: WorkerBaseSignals):
         """
         super().__init_subclass__()
         cls.signals = signals
-        
+
     def __init__(self, calib_window: MainWidget, calib: QLIPP_Calibration):
         """Initialize the worker object.
 
@@ -90,17 +94,20 @@ def _check_abort(self):
         """
         if self.abort_requested:
             self.aborted.emit()
-            raise TimeoutError('Stop Requested.')
-    
+            raise TimeoutError("Stop Requested.")
+
     def _write_meta_file(self, meta_file: str):
         self.calib.meta_file = meta_file
-        self.calib.write_metadata(notes=self.calib_window.ui.le_notes_field.text())
+        self.calib.write_metadata(
+            notes=self.calib_window.ui.le_notes_field.text()
+        )
 
 
 class CalibrationWorker(CalibrationWorkerBase, signals=CalibrationSignals):
     """
     Class to execute calibration
     """
+
     def __init__(self, calib_window, calib):
         super().__init__(calib_window, calib)
 
@@ -109,44 +116,48 @@ def work(self):
         Runs the full calibration algorithm and emits necessary signals.
         """
 
-        self.plot_sequence_emit.emit('Coarse')
+        self.plot_sequence_emit.emit("Coarse")
         self.calib.intensity_emitter = self.intensity_update
         self.calib.plot_sequence_emitter = self.plot_sequence_emit
         self.calib.get_full_roi()
-        self.progress_update.emit((1, 'Calculating Blacklevel...'))
+        self.progress_update.emit((1, "Calculating Blacklevel..."))
         self._check_abort()
 
         # Check if change of ROI is needed
         if self.calib_window.use_cropped_roi:
             rect = self.calib.check_and_get_roi()
-            self.calib_window.mmc.setROI(rect.x, rect.y, rect.width, rect.height)
+            self.calib_window.mmc.setROI(
+                rect.x, rect.y, rect.width, rect.height
+            )
             self.calib.ROI = (rect.x, rect.y, rect.width, rect.height)
 
         self._check_abort()
 
-        logging.info('Calculating Black Level ...')
-        logging.debug('Calculating Black Level ...')
+        logging.info("Calculating Black Level ...")
+        logging.debug("Calculating Black Level ...")
         self.calib.close_shutter_and_calc_blacklevel()
 
         # Calculate Blacklevel
-        logging.info(f'Black Level: {self.calib.I_Black:.0f}\n')
-        logging.debug(f'Black Level: {self.calib.I_Black:.0f}\n')
+        logging.info(f"Black Level: {self.calib.I_Black:.0f}\n")
+        logging.debug(f"Black Level: {self.calib.I_Black:.0f}\n")
 
         self._check_abort()
-        self.progress_update.emit((10, 'Calibrating Extinction State...'))
+        self.progress_update.emit((10, "Calibrating Extinction State..."))
 
         # Open shutter
         self.calib.open_shutter()
 
         # Set LC Wavelength:
         self.calib.set_wavelength(int(self.calib_window.wavelength))
-        if self.calib_window.calib_mode == 'MM-Retardance':
-            self.calib_window.mmc.setProperty(LC_DEVICE_NAME, 'Wavelength', self.calib_window.wavelength)
+        if self.calib_window.calib_mode == "MM-Retardance":
+            self.calib_window.mmc.setProperty(
+                LC_DEVICE_NAME, "Wavelength", self.calib_window.wavelength
+            )
 
         self._check_abort()
 
         # Optimize States
-        self._calibrate_4state() if self.calib_window.calib_scheme == '4-State' else self._calibrate_5state()
+        self._calibrate_4state() if self.calib_window.calib_scheme == "4-State" else self._calibrate_5state()
 
         # Reset shutter autoshutter
         self.calib.reset_shutter()
@@ -158,8 +169,12 @@ def work(self):
         self._check_abort()
 
         # Calculate Extinction
-        extinction_ratio = self.calib.calculate_extinction(self.calib.swing, self.calib.I_Black, self.calib.I_Ext,
-                                                           self.calib.I_Elliptical)
+        extinction_ratio = self.calib.calculate_extinction(
+            self.calib.swing,
+            self.calib.I_Black,
+            self.calib.I_Ext,
+            self.calib.I_Elliptical,
+        )
         self._check_abort()
 
         # Update main GUI with extinction ratio
@@ -183,7 +198,7 @@ def _meta_path(metadata_idx: str):
         # Write Metadata
         self._write_meta_file(meta_file)
         self.calib_file_emit.emit(self.calib.meta_file)
-        self.progress_update.emit((100, 'Finished'))
+        self.progress_update.emit((100, "Finished"))
 
         self._check_abort()
 
@@ -205,9 +220,9 @@ def _calibrate_4state(self):
         Run through the 4-state calibration algorithm
         """
 
-        search_radius = np.min((self.calib.swing/self.calib.ratio, 0.05))
+        search_radius = np.min((self.calib.swing / self.calib.ratio, 0.05))
 
-        self.calib.calib_scheme = '4-State'
+        self.calib.calib_scheme = "4-State"
 
         self._check_abort()
 
@@ -215,23 +230,23 @@ def _calibrate_4state(self):
         self.calib.opt_Iext()
 
         self._check_abort()
-        self.progress_update.emit((60, 'Calibrating State 1...'))
+        self.progress_update.emit((60, "Calibrating State 1..."))
 
         # Optimize first elliptical (reference) state
         self.calib.opt_I0()
-        self.progress_update.emit((65, 'Calibrating State 2...'))
+        self.progress_update.emit((65, "Calibrating State 2..."))
 
         self._check_abort()
 
         # Optimize 60 deg state
         self.calib.opt_I60(search_radius, search_radius)
-        self.progress_update.emit((75, 'Calibrating State 3...'))
+        self.progress_update.emit((75, "Calibrating State 3..."))
 
         self._check_abort()
 
         # Optimize 120 deg state
         self.calib.opt_I120(search_radius, search_radius)
-        self.progress_update.emit((85, 'Writing Metadata...'))
+        self.progress_update.emit((85, "Writing Metadata..."))
 
         self._check_abort()
 
@@ -239,35 +254,35 @@ def _calibrate_5state(self):
 
         search_radius = np.min((self.calib.swing, 0.05))
 
-        self.calib.calib_scheme = '5-State'
+        self.calib.calib_scheme = "5-State"
 
         # Optimize Extinction State
         self.calib.opt_Iext()
-        self.progress_update.emit((50, 'Calibrating State 1...'))
+        self.progress_update.emit((50, "Calibrating State 1..."))
 
         self._check_abort()
 
         # Optimize First elliptical state
         self.calib.opt_I0()
-        self.progress_update.emit((55, 'Calibrating State 2...'))
+        self.progress_update.emit((55, "Calibrating State 2..."))
 
         self._check_abort()
 
         # Optimize 45 deg state
         self.calib.opt_I45(search_radius, search_radius)
-        self.progress_update.emit((65, 'Calibrating State 3...'))
+        self.progress_update.emit((65, "Calibrating State 3..."))
 
         self._check_abort()
 
         # Optimize 90 deg state
         self.calib.opt_I90(search_radius, search_radius)
-        self.progress_update.emit((75, 'Calibrating State 4...'))
+        self.progress_update.emit((75, "Calibrating State 4..."))
 
         self._check_abort()
 
         # Optimize 135 deg state
         self.calib.opt_I135(search_radius, search_radius)
-        self.progress_update.emit((85, 'Writing Metadata...'))
+        self.progress_update.emit((85, "Writing Metadata..."))
 
         self._check_abort()
 
@@ -278,22 +293,28 @@ def _assess_calibration(self):
         """
 
         if self.calib.extinction_ratio >= 100:
-            self.calib_assessment.emit('good')
-            self.calib_assessment_msg.emit('Successful Calibration')
+            self.calib_assessment.emit("good")
+            self.calib_assessment_msg.emit("Successful Calibration")
         elif 80 <= self.calib.extinction_ratio < 100:
-            self.calib_assessment.emit('okay')
-            self.calib_assessment_msg.emit('Successful Calibration, Okay Extinction Ratio')
+            self.calib_assessment.emit("okay")
+            self.calib_assessment_msg.emit(
+                "Successful Calibration, Okay Extinction Ratio"
+            )
         else:
-            self.calib_assessment.emit('bad')
-            message = ("Possibilities are: a) linear polarizer and LC are not oriented properly, "
-                       "b) circular analyzer has wrong handedness, "
-                       "c) the condenser is not setup for Kohler illumination, "
-                       "d) a component, such as autofocus dichroic or sample chamber, distorts the polarization state")
+            self.calib_assessment.emit("bad")
+            message = (
+                "Possibilities are: a) linear polarizer and LC are not oriented properly, "
+                "b) circular analyzer has wrong handedness, "
+                "c) the condenser is not setup for Kohler illumination, "
+                "d) a component, such as autofocus dichroic or sample chamber, distorts the polarization state"
+            )
 
-            self.calib_assessment_msg.emit('Poor Extinction. '+message)
+            self.calib_assessment_msg.emit("Poor Extinction. " + message)
 
 
-class BackgroundCaptureWorker(CalibrationWorkerBase, signals=BackgroundSignals):
+class BackgroundCaptureWorker(
+    CalibrationWorkerBase, signals=BackgroundSignals
+):
     """
     Class to execute background capture.
     """
@@ -304,22 +325,27 @@ def __init__(self, calib_window, calib):
     def work(self):
 
         # Make the background folder
-        bg_path = os.path.join(self.calib_window.directory, self.calib_window.ui.le_bg_folder.text())
+        bg_path = os.path.join(
+            self.calib_window.directory,
+            self.calib_window.ui.le_bg_folder.text(),
+        )
         if not os.path.exists(bg_path):
             os.mkdir(bg_path)
         else:
 
             # increment background paths
             idx = 1
-            while os.path.exists(bg_path+f'_{idx}'):
+            while os.path.exists(bg_path + f"_{idx}"):
                 idx += 1
 
-            bg_path = bg_path+f'_{idx}'
-            for state_file in glob.glob(os.path.join(bg_path, 'State*')):
+            bg_path = bg_path + f"_{idx}"
+            for state_file in glob.glob(os.path.join(bg_path, "State*")):
                 os.remove(state_file)
 
-            if os.path.exists(os.path.join(bg_path, 'calibration_metadata.txt')):
-                os.remove(os.path.join(bg_path, 'calibration_metadata.txt'))
+            if os.path.exists(
+                os.path.join(bg_path, "calibration_metadata.txt")
+            ):
+                os.remove(os.path.join(bg_path, "calibration_metadata.txt"))
 
         self._check_abort()
 
@@ -328,12 +354,14 @@ def work(self):
         img_dim = (imgs.shape[-2], imgs.shape[-1])
 
         # initialize reconstructor
-        recon = initialize_reconstructor('birefringence',
-                                         image_dim=img_dim,
-                                         calibration_scheme=self.calib_window.calib_scheme,
-                                         wavelength_nm=self.calib_window.wavelength,
-                                         swing=self.calib_window.swing,
-                                         bg_correction='None')
+        recon = initialize_reconstructor(
+            "birefringence",
+            image_dim=img_dim,
+            calibration_scheme=self.calib_window.calib_scheme,
+            wavelength_nm=self.calib_window.wavelength,
+            swing=self.calib_window.swing,
+            bg_correction="None",
+        )
 
         self._check_abort()
 
@@ -347,25 +375,27 @@ def work(self):
         self._check_abort()
 
         # Convert retardance to nm
-        self.retardance = self.birefringence[0] / (2 * np.pi) * self.calib_window.wavelength
+        self.retardance = (
+            self.birefringence[0] / (2 * np.pi) * self.calib_window.wavelength
+        )
 
         # Save metadata file and emit imgs
-        meta_file = os.path.join(bg_path, 'calibration_metadata.txt')
+        meta_file = os.path.join(bg_path, "calibration_metadata.txt")
         self._write_meta_file(meta_file)
 
         # Update last calibration file
         note = self.calib_window.ui.le_notes_field.text()
 
-        with open(self.calib_window.last_calib_meta_file, 'r') as file:
+        with open(self.calib_window.last_calib_meta_file, "r") as file:
             current_json = json.load(file)
 
-        old_note = current_json['Notes']
-        if old_note is None or old_note == '' or old_note == note:
-            current_json['Notes'] = note
+        old_note = current_json["Notes"]
+        if old_note is None or old_note == "" or old_note == note:
+            current_json["Notes"] = note
         else:
-            current_json['Notes'] = old_note + ', ' + note
+            current_json["Notes"] = old_note + ", " + note
 
-        with open(self.calib_window.last_calib_meta_file, 'w') as file:
+        with open(self.calib_window.last_calib_meta_file, "w") as file:
             json.dump(current_json, file, indent=1)
 
         self._check_abort()
@@ -397,26 +427,25 @@ def _save_bg_recon(self, bg_path: StrOrBytesPath):
             position=0,
             data_shape=(1, 2, 1, rows, columns),
             chunk_size=(1, 1, 1, rows, columns),
-            chan_names=['Retardance', 'Orientation']
+            chan_names=["Retardance", "Orientation"],
         )
         writer.write(self.birefringence[:2], p=0, t=0, z=0)
         # save intensity trace visualization
         import matplotlib.pyplot as plt
+
         plt.imsave(
-            os.path.join(bg_recon_path,
-            "retardance.png"),
+            os.path.join(bg_recon_path, "retardance.png"),
             self.retardance,
-            cmap="gray"
+            cmap="gray",
         )
         plt.imsave(
-            os.path.join(bg_recon_path,
-            "orientation.png"),
-            self.birefringence[1], 
+            os.path.join(bg_recon_path, "orientation.png"),
+            self.birefringence[1],
             cmap="hsv",
             vmin=0,
-            vmax=np.pi
-            )
-        
+            vmax=np.pi,
+        )
+
 
 @thread_worker
 def load_calibration(calib, metadata: MetadataReader):
@@ -438,13 +467,17 @@ def load_calibration(calib, metadata: MetadataReader):
     def _set_calib_attrs(calib, metadata):
         """Set the retardance attributes in the recOrder Calibration object"""
         if calib.calib_scheme == "4-State":
-            lc_states = ['ext', '0', '60', '120']
+            lc_states = ["ext", "0", "60", "120"]
         elif calib.calib_scheme == "5-State":
-            lc_states = ['ext', '0', '45', '90', '135']
+            lc_states = ["ext", "0", "45", "90", "135"]
         else:
-            raise ValueError("Invalid calibration scheme in metadata: {calib.calib_scheme}")
+            raise ValueError(
+                "Invalid calibration scheme in metadata: {calib.calib_scheme}"
+            )
         for side in ("A", "B"):
-            retardance_values = metadata.__getattribute__("LC" + side + "_retardance")
+            retardance_values = metadata.__getattribute__(
+                "LC" + side + "_retardance"
+            )
             for i, state in enumerate(lc_states):
                 # set the retardance value attribute (e.g. 'lca_0')
                 retardance_name = "lc" + side.lower() + "_" + state
@@ -456,19 +489,27 @@ def _set_calib_attrs(calib, metadata):
 
     _set_calib_attrs(calib, metadata)
 
-    for state, lca, lcb in zip([f'State{i}' for i in range(5)], metadata.LCA_retardance, metadata.LCB_retardance):
+    for state, lca, lcb in zip(
+        [f"State{i}" for i in range(5)],
+        metadata.LCA_retardance,
+        metadata.LCB_retardance,
+    ):
         calib.define_lc_state(state, lca, lcb)
 
     # Calculate black level after loading these properties
     calib.intensity_emitter = MockEmitter()
     calib.close_shutter_and_calc_blacklevel()
     calib.open_shutter()
-    set_lc_state(calib.mmc, calib.group, 'State0')
+    set_lc_state(calib.mmc, calib.group, "State0")
     calib.I_Ext = snap_and_average(calib.snap_manager)
-    set_lc_state(calib.mmc, calib.group, 'State1')
+    set_lc_state(calib.mmc, calib.group, "State1")
     calib.I_Elliptical = snap_and_average(calib.snap_manager)
     calib.reset_shutter()
 
-    yield str(calib.calculate_extinction(calib.swing, calib.I_Black, calib.I_Ext, calib.I_Elliptical))
+    yield str(
+        calib.calculate_extinction(
+            calib.swing, calib.I_Black, calib.I_Ext, calib.I_Elliptical
+        )
+    )
 
     return calib
diff --git a/recOrder/plugin/workers/reconstruction_workers.py b/recOrder/plugin/workers/reconstruction_workers.py
index 3832b7cf..e6976bf6 100644
--- a/recOrder/plugin/workers/reconstruction_workers.py
+++ b/recOrder/plugin/workers/reconstruction_workers.py
@@ -4,6 +4,7 @@
 import time
 import os
 
+
 class ReconstructionSignals(WorkerBaseSignals):
     """
     Custom Signals class that includes napari native signals
@@ -15,7 +16,6 @@ class ReconstructionSignals(WorkerBaseSignals):
 
 
 class ReconstructionWorker(WorkerBase):
-
     def __init__(self, calib_window, config):
         super().__init__(SignalsClass=ReconstructionSignals)
 
@@ -26,17 +26,25 @@ def __init__(self, calib_window, config):
     def _check_abort(self):
         if self.abort_requested:
             self.aborted.emit()
-            raise TimeoutError('Stop Requested')
+            raise TimeoutError("Stop Requested")
 
     def work(self):
 
-        self.manager = PipelineManager(self.config, emitter=self.dimension_emitter)
-
-        store_path = os.path.join(self.manager.config.save_dir, self.manager.config.data_save_name)
-        store_path = store_path + '.zarr' if not store_path.endswith('.zarr') else store_path
+        self.manager = PipelineManager(
+            self.config, emitter=self.dimension_emitter
+        )
+
+        store_path = os.path.join(
+            self.manager.config.save_dir, self.manager.config.data_save_name
+        )
+        store_path = (
+            store_path + ".zarr"
+            if not store_path.endswith(".zarr")
+            else store_path
+        )
         self.store_emitter.emit(store_path)
 
-        print(f'Beginning Reconstruction...')
+        print(f"Beginning Reconstruction...")
 
         for pt in sorted(self.manager.pt_set):
             start_time = time.time()
@@ -45,7 +53,9 @@ def work(self):
 
             self._check_abort()
 
-            pt_data = self.manager.data.get_zarr(pt[0])[pt[1]]  # (C, Z, Y, X) virtual
+            pt_data = self.manager.data.get_zarr(pt[0])[
+                pt[1]
+            ]  # (C, Z, Y, X) virtual
 
             self._check_abort()
 
@@ -53,25 +63,39 @@ def work(self):
 
             self._check_abort()
 
-            birefringence = self.manager.pipeline.reconstruct_birefringence_volume(stokes)
+            birefringence = (
+                self.manager.pipeline.reconstruct_birefringence_volume(stokes)
+            )
 
             self._check_abort()
 
             # will return phase volumes
-            deconvolve2D, deconvolve3D = self.manager.pipeline.deconvolve_volume(stokes)
+            (
+                deconvolve2D,
+                deconvolve3D,
+            ) = self.manager.pipeline.deconvolve_volume(stokes)
 
             self._check_abort()
 
-            self.manager.pipeline.write_data(self.manager.indices_map[pt[0]], pt[1], pt_data, stokes,
-                                     birefringence, deconvolve2D, deconvolve3D)
+            self.manager.pipeline.write_data(
+                self.manager.indices_map[pt[0]],
+                pt[1],
+                pt_data,
+                stokes,
+                birefringence,
+                deconvolve2D,
+                deconvolve3D,
+            )
 
             self._check_abort()
 
             end_time = time.time()
-            print(f'Finishing Reconstructing P = {pt[0]}, T = {pt[1]} ({(end_time - start_time) / 60:0.2f}) min')
+            print(
+                f"Finishing Reconstructing P = {pt[0]}, T = {pt[1]} ({(end_time - start_time) / 60:0.2f}) min"
+            )
 
             existing_meta = self.manager.writer.store.attrs.asdict().copy()
-            existing_meta['Config'] = self.manager.config.yaml_dict
+            existing_meta["Config"] = self.manager.config.yaml_dict
             self.manager.writer.store.attrs.put(existing_meta)
 
             self._check_abort()
diff --git a/recOrder/scripts/cli.py b/recOrder/scripts/cli.py
index 0bddc2ee..506dc5c2 100644
--- a/recOrder/scripts/cli.py
+++ b/recOrder/scripts/cli.py
@@ -10,18 +10,20 @@ class ShowUsageOnMissingError(click.Command):
     def __call__(self, *args, **kwargs):
         try:
             return super(ShowUsageOnMissingError, self).__call__(
-                *args, standalone_mode=False, **kwargs)
+                *args, standalone_mode=False, **kwargs
+            )
         except click.MissingParameter as exc:
             exc.ctx = None
             exc.show(file=sys.stdout)
             click.echo()
             try:
-                super(ShowUsageOnMissingError, self).__call__(['--help'])
+                super(ShowUsageOnMissingError, self).__call__(["--help"])
             except SystemExit:
                 sys.exit(exc.exit_code)
 
+
 @click.command(cls=ShowUsageOnMissingError)
-@click.help_option('-h', '--help')
+@click.help_option("-h", "--help")
 def help():
     """\033[92mrecOrder: Computational Toolkit for Label-Free Imaging\033[0m
 
@@ -40,41 +42,106 @@ def help():
     """
     print(help.__doc__)
 
+
 @click.command(cls=ShowUsageOnMissingError)
-@click.help_option('-h', '--help')
-@click.option('--method', required=False, type=str, help='mode of reconstruction: \
-                                                      QLIPP, IPS, UPTI')
-@click.option('--mode', required=False, type=str, help='mode of reconstruction: \
-                                                      2D, 3D, Stokes')
-@click.option('--data_dir', required=False, type=click.Path(exists=True), help='path to the data')
-@click.option('--save_dir', required=False, type=click.Path(), help='path to the save directory')
-@click.option('--name', required=False, type=str, help='name to use for saving the data')
-@click.option('--config', required=True, type=click.Path(exists=True), help='path to config yml file')
-@click.option('--overwrite', required=False, type=bool,
-              help='whether or not to overwrite any previous data under this name')
-def reconstruct(method, mode, data_dir, save_dir, name, config, overwrite=False):
+@click.help_option("-h", "--help")
+@click.option(
+    "--method",
+    required=False,
+    type=str,
+    help="mode of reconstruction: \
+                                                      QLIPP, IPS, UPTI",
+)
+@click.option(
+    "--mode",
+    required=False,
+    type=str,
+    help="mode of reconstruction: \
+                                                      2D, 3D, Stokes",
+)
+@click.option(
+    "--data_dir",
+    required=False,
+    type=click.Path(exists=True),
+    help="path to the data",
+)
+@click.option(
+    "--save_dir",
+    required=False,
+    type=click.Path(),
+    help="path to the save directory",
+)
+@click.option(
+    "--name", required=False, type=str, help="name to use for saving the data"
+)
+@click.option(
+    "--config",
+    required=True,
+    type=click.Path(exists=True),
+    help="path to config yml file",
+)
+@click.option(
+    "--overwrite",
+    required=False,
+    type=bool,
+    help="whether or not to overwrite any previous data under this name",
+)
+def reconstruct(
+    method, mode, data_dir, save_dir, name, config, overwrite=False
+):
 
     if config:
         if not os.path.exists(config):
-            raise ValueError('Specified config path does not exist')
+            raise ValueError("Specified config path does not exist")
         else:
-            config = ConfigReader(config, data_dir, save_dir, method, mode, name,
-                                  immutable=False)
+            config = ConfigReader(
+                config, data_dir, save_dir, method, mode, name, immutable=False
+            )
             config.save_yaml()
     else:
-        config = ConfigReader(None, data_dir, save_dir, method, mode, name, immutable=False)
+        config = ConfigReader(
+            None, data_dir, save_dir, method, mode, name, immutable=False
+        )
         config.save_yaml()
 
     manager = PipelineManager(config, overwrite)
     manager.run()
 
+
 @click.command(cls=ShowUsageOnMissingError)
-@click.help_option('-h', '--help')
-@click.option('--input', required=True, type=click.Path(exists=True), help='path to the raw data folder containing ome.tifs')
-@click.option('--output', required=True, type=str, help='full path to save the zarr store (../../Experiment.zarr')
-@click.option('--data_type', required=False, type=str, help='Data type, "ometiff", "upti", "zarr"')
-@click.option('--replace_pos_name', required=False, type=bool, help='whether or not to append position name to data')
-@click.option('--format_hcs', required=False, type=bool, help='whether or not to format the data as an HCS "well-plate"')
+@click.help_option("-h", "--help")
+@click.option(
+    "--input",
+    required=True,
+    type=click.Path(exists=True),
+    help="path to the raw data folder containing ome.tifs",
+)
+@click.option(
+    "--output",
+    required=True,
+    type=str,
+    help="full path to save the zarr store (../../Experiment.zarr",
+)
+@click.option(
+    "--data_type",
+    required=False,
+    type=str,
+    help='Data type, "ometiff", "upti", "zarr"',
+)
+@click.option(
+    "--replace_pos_name",
+    required=False,
+    type=bool,
+    help="whether or not to append position name to data",
+)
+@click.option(
+    "--format_hcs",
+    required=False,
+    type=bool,
+    help='whether or not to format the data as an HCS "well-plate"',
+)
 def convert(input, output, data_type, replace_pos_name, format_hcs):
-    converter = ZarrConverter(input, output, data_type, replace_pos_name, format_hcs)
-    converter.run_conversion()
\ No newline at end of file
+    converter = ZarrConverter(
+        input, output, data_type, replace_pos_name, format_hcs
+    )
+    converter.run_conversion()
diff --git a/recOrder/scripts/launch_napari.py b/recOrder/scripts/launch_napari.py
index c9c6cd61..40043651 100644
--- a/recOrder/scripts/launch_napari.py
+++ b/recOrder/scripts/launch_napari.py
@@ -9,4 +9,4 @@ def main():
 
 
 if __name__ == "__main__":
-    main()
\ No newline at end of file
+    main()
diff --git a/recOrder/scripts/md5_check_sum.py b/recOrder/scripts/md5_check_sum.py
index a3c39d0f..14ba4648 100644
--- a/recOrder/scripts/md5_check_sum.py
+++ b/recOrder/scripts/md5_check_sum.py
@@ -5,19 +5,28 @@
 import pathlib as path
 import click
 
+
 @click.command()
-@click.option('--zarr_path', required=True, type=str, help='path to the save directory')
-@click.option('--raw_stats_path', required=True, type=str, help='path to the statistics file of the raw data')
+@click.option(
+    "--zarr_path", required=True, type=str, help="path to the save directory"
+)
+@click.option(
+    "--raw_stats_path",
+    required=True,
+    type=str,
+    help="path to the statistics file of the raw data",
+)
 def parse_args(zarr_path, raw_stats_path):
     """parse command line arguments and return class with the arguments"""
 
-    class Args():
+    class Args:
         def __init__(self, zarr_path, raw_stats_path):
             self.zarr_path = zarr_path
             self.raw_stats_path = raw_stats_path
 
     return Args(zarr_path, raw_stats_path)
 
+
 def md5(fname):
     hash_md5 = hashlib.md5()
     with open(fname, "rb") as f:
@@ -25,15 +34,16 @@ def md5(fname):
             hash_md5.update(chunk)
     return hash_md5.hexdigest()
 
+
 def gen_stats_file(zarr_path, save_path):
 
     name = path.PurePath(zarr_path).name
-    if name.endswith('.zarr'):
+    if name.endswith(".zarr"):
         name = name[:-5]
-    file_name = os.path.join(save_path, name+'_ZarrStatistics.txt')
-    file = open(file_name, 'w')
+    file_name = os.path.join(save_path, name + "_ZarrStatistics.txt")
+    file = open(file_name, "w")
 
-    zstore = zarr.open(zarr_path, 'r')['array']
+    zstore = zarr.open(zarr_path, "r")["array"]
     shape = zstore.shape
 
     for p in range(shape[0]):
@@ -45,7 +55,9 @@ def gen_stats_file(zarr_path, save_path):
                     mean = np.mean(image)
                     median = np.median(image)
                     std = np.std(image)
-                    file.write(f'Coord: {(p, t, c, z)}, Mean: {mean}, Median: {median}, Std: {std}\n')
+                    file.write(
+                        f"Coord: {(p, t, c, z)}, Mean: {mean}, Median: {median}, Std: {std}\n"
+                    )
 
     file.close()
     return file_name
@@ -62,11 +74,6 @@ def gen_stats_file(zarr_path, save_path):
     converted_md5 = md5(conv_stats_path)
 
     if raw_md5 != converted_md5:
-        print('MD5 check sum failed.  Potential Error in Conversion')
+        print("MD5 check sum failed.  Potential Error in Conversion")
     else:
-        print('MD5 check sum passed. Conversion successful')
-
-
-
-
-
+        print("MD5 check sum passed. Conversion successful")
diff --git a/recOrder/scripts/repeat-cal-acq-rec.py b/recOrder/scripts/repeat-cal-acq-rec.py
index 9e63beeb..912f5679 100644
--- a/recOrder/scripts/repeat-cal-acq-rec.py
+++ b/recOrder/scripts/repeat-cal-acq-rec.py
@@ -71,11 +71,16 @@ def measure_fov(mmc: Core):
     """
     pixel_size = float(mmc.getPixelSizeUm())
     if pixel_size == 0:
-        float(input("Pixel size is not calibrated. Please provide an estimate (in microns):"))
+        float(
+            input(
+                "Pixel size is not calibrated. Please provide an estimate (in microns):"
+            )
+        )
     fov_x = pixel_size * float(mmc.getImageWidth())
     fov_y = pixel_size * float(mmc.getImageHeight())
     return fov_x, fov_y
 
+
 def rand_shift(length: float):
     """Randomly signed shift of a certain length.
 
@@ -92,12 +97,13 @@ def rand_shift(length: float):
     sign = random.randint(0, 1) * 2 - 1
     return sign * length
 
+
 def main():
     viewer = napari.Viewer()
     app = MainWidget(viewer)
     viewer.window.add_dock_widget(app)
     app.ui.qbutton_gui_mode.click()
-    app.calib_scheme = '5-State'
+    app.calib_scheme = "5-State"
     app.directory = SAVE_DIR
     app.save_directory = SAVE_DIR
 
@@ -112,7 +118,7 @@ def main():
         with stage_detour(app, dx, dy) as app:
             print(f"Calibration repeat # {cal_repeat}")
             app.swing = SWING
-        
+
             print(f"Calibrating with swing = {SWING}")
             app.run_calibration()
             time.sleep(90)
@@ -124,12 +130,15 @@ def main():
                 app.last_calib_meta_file = app.calib.meta_file
                 app.capture_bg()
                 time.sleep(20)
-            app.ui.cb_bg_method.setCurrentIndex(1) # Set to "Measured" bg correction
+            app.ui.cb_bg_method.setCurrentIndex(
+                1
+            )  # Set to "Measured" bg correction
             app.enter_bg_correction()
             app.save_name = f"cal-{cal_repeat}-bkg-{bkg_repeat}"
             app.enter_acq_bg_path()
             app.acq_birefringence()
             time.sleep(15)
 
+
 if __name__ == "__main__":
-    main()
\ No newline at end of file
+    main()
diff --git a/recOrder/scripts/repeat-calibration.py b/recOrder/scripts/repeat-calibration.py
index 56d04df7..a2a61283 100644
--- a/recOrder/scripts/repeat-calibration.py
+++ b/recOrder/scripts/repeat-calibration.py
@@ -8,12 +8,13 @@
 SWINGS = [0.1, 0.03, 0.01, 0.005]
 REPEATS = 5
 
+
 def main():
     viewer = napari.Viewer()
     recorder = MainWidget(viewer)
     viewer.window.add_dock_widget(recorder)
     recorder.ui.qbutton_gui_mode.click()
-    recorder.calib_scheme = '5-State'
+    recorder.calib_scheme = "5-State"
 
     for repeat in range(REPEATS):
         for swing in SWINGS:
@@ -22,6 +23,7 @@ def main():
             recorder.directory = SAVE_DIR
             recorder.run_calibration()
             time.sleep(100)
-            
+
+
 if __name__ == "__main__":
-    main()
\ No newline at end of file
+    main()


Test patch:
diff --git a/recOrder/tests/calibration_tests/test_calibration.py b/recOrder/tests/calibration_tests/test_calibration.py
index 408e1ccb..08ba1239 100644
--- a/recOrder/tests/calibration_tests/test_calibration.py
+++ b/recOrder/tests/calibration_tests/test_calibration.py
@@ -1,2 +1,2 @@
 def test_calib_imports():
-    from recOrder.calib import Calibration, Optimization
\ No newline at end of file
+    from recOrder.calib import Calibration, Optimization
diff --git a/recOrder/tests/config_reader_tests/test_config_reader.py b/recOrder/tests/config_reader_tests/test_config_reader.py
index fa3420f4..3e23b701 100644
--- a/recOrder/tests/config_reader_tests/test_config_reader.py
+++ b/recOrder/tests/config_reader_tests/test_config_reader.py
@@ -3,36 +3,49 @@
 from os.path import dirname, abspath
 import yaml
 
+
 def test_config_reader(get_zarr_data_dir):
 
     folder, zarr_data = get_zarr_data_dir
-    path_to_config = os.path.join(dirname(dirname(abspath(__file__))), 'test_configs/qlipp/config_qlipp_full_pytest.yml')
+    path_to_config = os.path.join(
+        dirname(dirname(abspath(__file__))),
+        "test_configs/qlipp/config_qlipp_full_pytest.yml",
+    )
 
     raw = yaml.full_load(open(path_to_config))
     config = ConfigReader(path_to_config, data_dir=zarr_data, save_dir=folder)
 
-    avoid = ['data_dir', 'save_dir', 'data_save_name', 'positions', 'timepoints',
-             'background_ROI', 'qlipp_birefringence_only', 'phase_denoiser_2D',
-             'Tik_reg_abs_2D', 'Tik_reg_ph_2D', 'rho_2D', 'itr_2D', 'TV_reg_abs_2D',
-             'TV_reg_ph_2D', 'brightfield_channel_index',
-             'reg']
+    avoid = [
+        "data_dir",
+        "save_dir",
+        "data_save_name",
+        "positions",
+        "timepoints",
+        "background_ROI",
+        "qlipp_birefringence_only",
+        "phase_denoiser_2D",
+        "Tik_reg_abs_2D",
+        "Tik_reg_ph_2D",
+        "rho_2D",
+        "itr_2D",
+        "TV_reg_abs_2D",
+        "TV_reg_ph_2D",
+        "brightfield_channel_index",
+        "reg",
+    ]
 
     for key, value in DATASET.items():
         if key not in avoid:
-            assert(raw['dataset'][key] == getattr(config, key))
+            assert raw["dataset"][key] == getattr(config, key)
 
-    assert(folder == config.save_dir)
-    assert(zarr_data == config.data_dir)
-    assert([raw['dataset']['positions']] == config.positions)
-    assert([raw['dataset']['timepoints']] == config.timepoints)
-    assert(config.background_ROI == None)
+    assert folder == config.save_dir
+    assert zarr_data == config.data_dir
+    assert [raw["dataset"]["positions"]] == config.positions
+    assert [raw["dataset"]["timepoints"]] == config.timepoints
+    assert config.background_ROI == None
 
     for key, value in PROCESSING.items():
         if key not in avoid:
-            assert(raw['processing'][key] == getattr(config, key))
-
-    assert(config.qlipp_birefringence_only == False)
-
-
-
+            assert raw["processing"][key] == getattr(config, key)
 
+    assert config.qlipp_birefringence_only == False
diff --git a/recOrder/tests/conftest.py b/recOrder/tests/conftest.py
index 97c1a918..9f8b3868 100644
--- a/recOrder/tests/conftest.py
+++ b/recOrder/tests/conftest.py
@@ -5,11 +5,12 @@
 from recOrder.pipelines.pipeline_manager import PipelineManager
 from wget import download
 
+
 @pytest.fixture(scope="session")
 def setup_test_data():
     # create /pytest_temp/ and /pytest_temp/rawdata/ folders,
-    temp_folder = os.path.join(os.getcwd(), 'pytest_temp')
-    test_data = os.path.join(temp_folder, 'test_data')
+    temp_folder = os.path.join(os.getcwd(), "pytest_temp")
+    test_data = os.path.join(temp_folder, "test_data")
     if not os.path.isdir(temp_folder):
         os.mkdir(temp_folder)
         print("\nsetting up temp folder")
@@ -17,7 +18,7 @@ def setup_test_data():
         os.mkdir(test_data)
 
     #  download data to /pytest_temp/ folder if it doesn't already exist
-    url = 'https://zenodo.org/record/6983916/files/recOrder_test_data.zip?download=1'
+    url = "https://zenodo.org/record/6983916/files/recOrder_test_data.zip?download=1"
     output = os.path.join(test_data, "recOrder_test_Data.zip")
     if not os.listdir(test_data):
         print("Downloading test files...")
@@ -26,12 +27,16 @@ def setup_test_data():
 
     yield test_data
 
+
 @pytest.fixture()
 def get_ometiff_data_dir(setup_test_data):
     test_data = setup_test_data
 
-    ometiff_data = os.path.join(test_data,
-                                '2022_08_04_recOrder_pytest_20x_04NA', '2T_3P_16Z_128Y_256X_Kazansky_1')
+    ometiff_data = os.path.join(
+        test_data,
+        "2022_08_04_recOrder_pytest_20x_04NA",
+        "2T_3P_16Z_128Y_256X_Kazansky_1",
+    )
 
     return test_data, ometiff_data
 
@@ -40,8 +45,11 @@ def get_ometiff_data_dir(setup_test_data):
 def get_zarr_data_dir(setup_test_data):
     test_data = setup_test_data
 
-    zarr_data = os.path.join(test_data,
-                             '2022_08_04_recOrder_pytest_20x_04NA_zarr', '2T_3P_16Z_128Y_256X_Kazansky.zarr')
+    zarr_data = os.path.join(
+        test_data,
+        "2022_08_04_recOrder_pytest_20x_04NA_zarr",
+        "2T_3P_16Z_128Y_256X_Kazansky.zarr",
+    )
 
     return test_data, zarr_data
 
@@ -50,8 +58,11 @@ def get_zarr_data_dir(setup_test_data):
 def get_bf_data_dir(setup_test_data):
     test_data = setup_test_data
 
-    bf_data = os.path.join(test_data,
-                           '2022_08_04_recOrder_pytest_20x_04NA_BF', '2T_3P_16Z_128Y_256X_Kazansky_BF_1')
+    bf_data = os.path.join(
+        test_data,
+        "2022_08_04_recOrder_pytest_20x_04NA_BF",
+        "2T_3P_16Z_128Y_256X_Kazansky_BF_1",
+    )
 
     return test_data, bf_data
 
@@ -60,18 +71,25 @@ def get_bf_data_dir(setup_test_data):
 def get_pycromanager_data_dir(setup_test_data):
     test_data = setup_test_data
 
-    pm_data = os.path.join(test_data, 'mm2.0-20210713_pm0.13.2_2p_3t_2c_7z_1')
+    pm_data = os.path.join(test_data, "mm2.0-20210713_pm0.13.2_2p_3t_2c_7z_1")
 
     return test_data, pm_data
 
+
 @pytest.fixture()
 def init_phase_bf_pipeline_manager(get_bf_data_dir, setup_data_save_folder):
     folder, bf_data = get_bf_data_dir
     save_folder = setup_data_save_folder
 
     file_path = os.path.dirname(__file__)
-    path_to_config = os.path.abspath(os.path.join(file_path, './test_configs/phase/config_phase_full_pytest.yml'))
-    config = ConfigReader(path_to_config, data_dir=bf_data, save_dir=save_folder)
+    path_to_config = os.path.abspath(
+        os.path.join(
+            file_path, "./test_configs/phase/config_phase_full_pytest.yml"
+        )
+    )
+    config = ConfigReader(
+        path_to_config, data_dir=bf_data, save_dir=save_folder
+    )
     manager = PipelineManager(config)
 
     return save_folder, config, manager
@@ -83,31 +101,45 @@ def init_qlipp_pipeline_manager(get_zarr_data_dir, setup_data_save_folder):
     save_folder = setup_data_save_folder
 
     file_path = os.path.dirname(__file__)
-    path_to_config = os.path.abspath(os.path.join(file_path, './test_configs/qlipp/config_qlipp_full_pytest.yml'))
-    config = ConfigReader(path_to_config, data_dir=zarr_data, save_dir=save_folder)
+    path_to_config = os.path.abspath(
+        os.path.join(
+            file_path, "./test_configs/qlipp/config_qlipp_full_pytest.yml"
+        )
+    )
+    config = ConfigReader(
+        path_to_config, data_dir=zarr_data, save_dir=save_folder
+    )
     manager = PipelineManager(config)
 
     return save_folder, config, manager
 
 
 @pytest.fixture()
-def init_qlipp_tiff_pipeline_manager(get_ometiff_data_dir, setup_data_save_folder):
+def init_qlipp_tiff_pipeline_manager(
+    get_ometiff_data_dir, setup_data_save_folder
+):
     folder, ometiff_data = get_ometiff_data_dir
     save_folder = setup_data_save_folder
 
     file_path = os.path.dirname(__file__)
-    path_to_config = os.path.abspath(os.path.join(file_path, './test_configs/qlipp/config_qlipp_full_pytest_tiff.yml'))
-    config = ConfigReader(path_to_config, data_dir=ometiff_data, save_dir=save_folder)
+    path_to_config = os.path.abspath(
+        os.path.join(
+            file_path, "./test_configs/qlipp/config_qlipp_full_pytest_tiff.yml"
+        )
+    )
+    config = ConfigReader(
+        path_to_config, data_dir=ometiff_data, save_dir=save_folder
+    )
     manager = PipelineManager(config)
 
     return save_folder, config, manager
 
 
 # create /pytest_temp/data_save folder for each test then delete when test is done
-@pytest.fixture(scope='function')
+@pytest.fixture(scope="function")
 def setup_data_save_folder():
-    temp_folder = os.path.join(os.getcwd(), 'pytest_temp')
-    data_save_folder = os.path.join(temp_folder, 'data_save')
+    temp_folder = os.path.join(os.getcwd(), "pytest_temp")
+    data_save_folder = os.path.join(temp_folder, "data_save")
     if not os.path.isdir(data_save_folder):
         os.mkdir(data_save_folder)
         print("\nsetting up data_save folder")
diff --git a/recOrder/tests/converter_tests/test_converter.py b/recOrder/tests/converter_tests/test_converter.py
index 27ee6b90..5e76bacf 100644
--- a/recOrder/tests/converter_tests/test_converter.py
+++ b/recOrder/tests/converter_tests/test_converter.py
@@ -6,35 +6,45 @@
 import numpy as np
 from recOrder.io.zarr_converter import ZarrConverter
 
-def test_ometiff_converter_initialize(setup_data_save_folder, get_ometiff_data_dir):
+
+def test_ometiff_converter_initialize(
+    setup_data_save_folder, get_ometiff_data_dir
+):
 
     folder, ometiff_data = get_ometiff_data_dir
     save_folder = setup_data_save_folder
 
     input = ometiff_data
-    output = os.path.join(save_folder, '2T_3P_16Z_128Y_256X_Kazansky.zarr')
+    output = os.path.join(save_folder, "2T_3P_16Z_128Y_256X_Kazansky.zarr")
 
     if os.path.exists(output):
         shutil.rmtree(output)
 
     converter = ZarrConverter(input, output)
 
-    with TiffFile(os.path.join(ometiff_data, '2T_3P_16Z_128Y_256X_Kazansky_1_MMStack_Pos0.ome.tif')) as tf:
-        assert (converter.summary_metadata == tf.micromanager_metadata['Summary'])
-
-    assert(converter.dtype == 'uint16')
-    assert(isinstance(converter.reader, WaveorderReader))
-    assert(isinstance(converter.writer, WaveorderWriter))
+    with TiffFile(
+        os.path.join(
+            ometiff_data, "2T_3P_16Z_128Y_256X_Kazansky_1_MMStack_Pos0.ome.tif"
+        )
+    ) as tf:
+        assert (
+            converter.summary_metadata == tf.micromanager_metadata["Summary"]
+        )
+
+    assert converter.dtype == "uint16"
+    assert isinstance(converter.reader, WaveorderReader)
+    assert isinstance(converter.writer, WaveorderWriter)
+
+    assert converter.dim_order == ["time", "position", "z", "channel"]
+    assert converter.p_dim == 1
+    assert converter.t_dim == 0
+    assert converter.c_dim == 3
+    assert converter.z_dim == 2
+    assert converter.p == 3
+    assert converter.t == 2
+    assert converter.c == 4
+    assert converter.z == 16
 
-    assert(converter.dim_order == ['time', 'position', 'z', 'channel'])
-    assert(converter.p_dim == 1)
-    assert(converter.t_dim == 0)
-    assert(converter.c_dim == 3)
-    assert(converter.z_dim == 2)
-    assert(converter.p == 3)
-    assert(converter.t == 2)
-    assert(converter.c == 4)
-    assert(converter.z == 16)
 
 def test_ometiff_converter_run(setup_data_save_folder, get_ometiff_data_dir):
 
@@ -42,7 +52,7 @@ def test_ometiff_converter_run(setup_data_save_folder, get_ometiff_data_dir):
     save_folder = setup_data_save_folder
 
     input = ometiff_data
-    output = os.path.join(save_folder, '2T_3P_16Z_128Y_256X_Kazansky.zarr')
+    output = os.path.join(save_folder, "2T_3P_16Z_128Y_256X_Kazansky.zarr")
 
     if os.path.exists(output):
         shutil.rmtree(output)
@@ -50,57 +60,78 @@ def test_ometiff_converter_run(setup_data_save_folder, get_ometiff_data_dir):
     converter = ZarrConverter(input, output)
 
     converter.run_conversion()
-    zs = zarr.open(output, 'r')
+    zs = zarr.open(output, "r")
 
-    assert(os.path.exists(os.path.join(save_folder, '2T_3P_16Z_128Y_256X_Kazansky_ImagePlaneMetadata.txt')))
+    assert os.path.exists(
+        os.path.join(
+            save_folder, "2T_3P_16Z_128Y_256X_Kazansky_ImagePlaneMetadata.txt"
+        )
+    )
 
     cnt = 0
     for t in range(2):
         for p in range(3):
-            cnt = t*16*4
-            tf = TiffFile(os.path.join(ometiff_data, f'2T_3P_16Z_128Y_256X_Kazansky_1_MMStack_Pos{p}.ome.tif'))
+            cnt = t * 16 * 4
+            tf = TiffFile(
+                os.path.join(
+                    ometiff_data,
+                    f"2T_3P_16Z_128Y_256X_Kazansky_1_MMStack_Pos{p}.ome.tif",
+                )
+            )
             for z in range(16):
                 for c in range(4):
-                    image = zs['Row_0'][f'Col_{p}'][f'Pos_00{p}']['arr_0'][t, c, z]
+                    image = zs["Row_0"][f"Col_{p}"][f"Pos_00{p}"]["arr_0"][
+                        t, c, z
+                    ]
                     tiff_image = tf.pages.get(cnt).asarray()
-                    assert(np.array_equal(image, tiff_image))
+                    assert np.array_equal(image, tiff_image)
                     cnt += 1
             tf.close()
 
-def test_pycromanager_converter_initialize(setup_data_save_folder, get_pycromanager_data_dir):
+
+def test_pycromanager_converter_initialize(
+    setup_data_save_folder, get_pycromanager_data_dir
+):
 
     folder, pm_data = get_pycromanager_data_dir
     save_folder = setup_data_save_folder
 
     input = pm_data
-    output = os.path.join(save_folder, 'mm2.0-20210713_pm0.13.2_2p_3t_2c_7z_1.zarr')
+    output = os.path.join(
+        save_folder, "mm2.0-20210713_pm0.13.2_2p_3t_2c_7z_1.zarr"
+    )
 
     if os.path.exists(output):
         shutil.rmtree(output)
 
     converter = ZarrConverter(input, output)
 
-    assert(isinstance(converter.reader, WaveorderReader))
-    assert(isinstance(converter.writer, WaveorderWriter))
+    assert isinstance(converter.reader, WaveorderReader)
+    assert isinstance(converter.writer, WaveorderWriter)
     assert converter.summary_metadata is not None
 
-    assert(converter.dim_order == ['position', 'time', 'channel', 'z'])
-    assert(converter.p_dim == 0)
-    assert(converter.t_dim == 1)
-    assert(converter.c_dim == 2)
-    assert(converter.z_dim == 3)
-    assert(converter.p == 2)
-    assert(converter.t == 3)
-    assert(converter.c == 2)
-    assert(converter.z == 7)
+    assert converter.dim_order == ["position", "time", "channel", "z"]
+    assert converter.p_dim == 0
+    assert converter.t_dim == 1
+    assert converter.c_dim == 2
+    assert converter.z_dim == 3
+    assert converter.p == 2
+    assert converter.t == 3
+    assert converter.c == 2
+    assert converter.z == 7
+
 
-def test_pycromanager_converter_run(setup_data_save_folder, get_pycromanager_data_dir):
+def test_pycromanager_converter_run(
+    setup_data_save_folder, get_pycromanager_data_dir
+):
 
     folder, pm_data = get_pycromanager_data_dir
     save_folder = setup_data_save_folder
 
     input = pm_data
-    output = os.path.join(save_folder, 'mm2.0-20210713_pm0.13.2_2p_3t_2c_7z_1.zarr')
+    output = os.path.join(
+        save_folder, "mm2.0-20210713_pm0.13.2_2p_3t_2c_7z_1.zarr"
+    )
 
     if os.path.exists(output):
         shutil.rmtree(output)
@@ -109,16 +140,23 @@ def test_pycromanager_converter_run(setup_data_save_folder, get_pycromanager_dat
     wo_dataset = WaveorderReader(input)
 
     converter.run_conversion()
-    zs = zarr.open(output, 'r')
+    zs = zarr.open(output, "r")
 
-    assert(os.path.exists(os.path.join(save_folder, 'mm2.0-20210713_pm0.13.2_2p_3t_2c_7z_1_ImagePlaneMetadata.txt')))
+    assert os.path.exists(
+        os.path.join(
+            save_folder,
+            "mm2.0-20210713_pm0.13.2_2p_3t_2c_7z_1_ImagePlaneMetadata.txt",
+        )
+    )
 
     cnt = 0
     for t in range(3):
         for p in range(2):
             for c in range(2):
                 for z in range(7):
-                    image = zs['Row_0'][f'Col_{p}'][f'Pos_00{p}']['arr_0'][t, c, z]
+                    image = zs["Row_0"][f"Col_{p}"][f"Pos_00{p}"]["arr_0"][
+                        t, c, z
+                    ]
                     wo_image = wo_dataset.get_image(p, t, c, z)
-                    assert(np.array_equal(image, wo_image))
+                    assert np.array_equal(image, wo_image)
                     cnt += 1
diff --git a/recOrder/tests/pipeline_tests/test_old_processing.py b/recOrder/tests/pipeline_tests/test_old_processing.py
index 6ced58f1..53040c93 100644
--- a/recOrder/tests/pipeline_tests/test_old_processing.py
+++ b/recOrder/tests/pipeline_tests/test_old_processing.py
@@ -1,20 +1,28 @@
 from recOrder.io.config_reader import ConfigReader
 from recOrder.pipelines.pipeline_manager import PipelineManager
-from recOrder.compute.qlipp_compute import reconstruct_qlipp_stokes, reconstruct_qlipp_birefringence
+from recOrder.compute.qlipp_compute import (
+    reconstruct_qlipp_stokes,
+    reconstruct_qlipp_birefringence,
+)
 from os.path import dirname, abspath
 import numpy as np
 import os
 import zarr
 
+
 def test_old_processing(get_ometiff_data_dir, setup_data_save_folder):
 
     folder, ometiff_data = get_ometiff_data_dir
     save_folder = setup_data_save_folder
 
-    path_to_config = os.path.join(dirname(dirname(abspath(__file__))),
-                                  'test_configs/config_old_processing_pytest.yml')
+    path_to_config = os.path.join(
+        dirname(dirname(abspath(__file__))),
+        "test_configs/config_old_processing_pytest.yml",
+    )
 
-    config = ConfigReader(path_to_config, data_dir=ometiff_data, save_dir=save_folder)
+    config = ConfigReader(
+        path_to_config, data_dir=ometiff_data, save_dir=save_folder
+    )
 
     manager = PipelineManager(config)
 
@@ -24,18 +32,34 @@ def test_old_processing(get_ometiff_data_dir, setup_data_save_folder):
     data = manager.data.get_array(pos)
     recon = manager.pipeline.reconstructor
 
-    stokes = reconstruct_qlipp_stokes(data[t], recon, manager.pipeline.bg_stokes)
-    params = [['S0', 0.5, 1], ['S1', 0.5, 1], ['S2', 0.5, 1], ['S3', 0.5, 1]]
-    
-    store = zarr.open(os.path.join(save_folder, '2T_3P_16Z_128Y_256X_Kazansky_1.zarr'), 'r')
-    array = store['Row_0']['Col_0']['Pos_001']['arr_0']
+    stokes = reconstruct_qlipp_stokes(
+        data[t], recon, manager.pipeline.bg_stokes
+    )
+    params = [["S0", 0.5, 1], ["S1", 0.5, 1], ["S2", 0.5, 1], ["S3", 0.5, 1]]
+
+    store = zarr.open(
+        os.path.join(save_folder, "2T_3P_16Z_128Y_256X_Kazansky_1.zarr"), "r"
+    )
+    array = store["Row_0"]["Col_0"]["Pos_001"]["arr_0"]
 
     # Check Stokes
-    assert (np.sum(np.abs(stokes[0, z, :, :] - array[0, 0, z]) ** 2) / np.sum(
-        np.abs(stokes[0, z, :, :])) ** 2 < 0.1)
-    assert (np.sum(np.abs(stokes[1, z, :, :] - array[0, 1, z]) ** 2) / np.sum(
-        np.abs(stokes[1, z, :, :])) ** 2 < 0.1)
-    assert (np.sum(np.abs(stokes[2, z, :, :] - array[0, 2, z]) ** 2) / np.sum(
-        np.abs(stokes[2, z, :, :])) ** 2 < 0.1)
-    assert (np.sum(np.abs(stokes[3, z, :, :] - array[0, 3, z]) ** 2) / np.sum(
-        np.abs(stokes[3, z, :, :])) ** 2 < 0.1)
\ No newline at end of file
+    assert (
+        np.sum(np.abs(stokes[0, z, :, :] - array[0, 0, z]) ** 2)
+        / np.sum(np.abs(stokes[0, z, :, :])) ** 2
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[1, z, :, :] - array[0, 1, z]) ** 2)
+        / np.sum(np.abs(stokes[1, z, :, :])) ** 2
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[2, z, :, :] - array[0, 2, z]) ** 2)
+        / np.sum(np.abs(stokes[2, z, :, :])) ** 2
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[3, z, :, :] - array[0, 3, z]) ** 2)
+        / np.sum(np.abs(stokes[3, z, :, :])) ** 2
+        < 0.1
+    )
diff --git a/recOrder/tests/pipeline_tests/test_phase_from_bf_pipeline.py b/recOrder/tests/pipeline_tests/test_phase_from_bf_pipeline.py
index df1c5a95..21ee9ef4 100644
--- a/recOrder/tests/pipeline_tests/test_phase_from_bf_pipeline.py
+++ b/recOrder/tests/pipeline_tests/test_phase_from_bf_pipeline.py
@@ -2,109 +2,172 @@
 from recOrder.pipelines.pipeline_manager import PipelineManager
 from recOrder.pipelines.phase_from_bf_pipeline import PhaseFromBF
 from waveorder.io.writer import WaveorderWriter
-from recOrder.compute.qlipp_compute import reconstruct_phase3D, reconstruct_phase2D
+from recOrder.compute.qlipp_compute import (
+    reconstruct_phase3D,
+    reconstruct_phase2D,
+)
 from os.path import dirname, abspath
 import numpy as np
 import os
 import zarr
 
+
 def test_pipeline_manager_initiate(init_phase_bf_pipeline_manager):
 
     save_folder, config, manager = init_phase_bf_pipeline_manager
 
-    assert(manager.config is not None)
-    assert(manager.data is not None)
-    assert(manager.data.get_num_positions()*manager.data.frames == len(manager.pt_set))
-    assert(manager.pipeline is not None)
-    assert(isinstance(manager.pipeline, PhaseFromBF))
+    assert manager.config is not None
+    assert manager.data is not None
+    assert manager.data.get_num_positions() * manager.data.frames == len(
+        manager.pt_set
+    )
+    assert manager.pipeline is not None
+    assert isinstance(manager.pipeline, PhaseFromBF)
+
 
 def test_bf_pipeline_initiate(init_phase_bf_pipeline_manager):
 
     save_folder, config, manager = init_phase_bf_pipeline_manager
 
     pipeline = manager.pipeline
-    assert(pipeline.config == manager.config)
-    assert(pipeline.data == manager.data)
-    assert(pipeline.t == manager.num_t)
-    assert(pipeline.mode == '3D')
-    assert(pipeline.slices == manager.data.slices)
-    assert(pipeline.img_dim == (manager.data.height, manager.data.width, manager.data.slices))
-    assert(pipeline.bf_chan_idx == 0)
-    assert(pipeline.data_shape == (manager.data.frames, manager.data.channels,
-                                   manager.data.slices, manager.data.height, manager.data.width))
-    assert(pipeline.chunk_size == (1, 1, 1, manager.data.height, manager.data.width))
-    assert(isinstance(pipeline.writer, WaveorderWriter))
-    assert(pipeline.reconstructor is not None)
+    assert pipeline.config == manager.config
+    assert pipeline.data == manager.data
+    assert pipeline.t == manager.num_t
+    assert pipeline.mode == "3D"
+    assert pipeline.slices == manager.data.slices
+    assert pipeline.img_dim == (
+        manager.data.height,
+        manager.data.width,
+        manager.data.slices,
+    )
+    assert pipeline.bf_chan_idx == 0
+    assert pipeline.data_shape == (
+        manager.data.frames,
+        manager.data.channels,
+        manager.data.slices,
+        manager.data.height,
+        manager.data.width,
+    )
+    assert pipeline.chunk_size == (
+        1,
+        1,
+        1,
+        manager.data.height,
+        manager.data.width,
+    )
+    assert isinstance(pipeline.writer, WaveorderWriter)
+    assert pipeline.reconstructor is not None
+
 
 def test_pipeline_manager_run(init_phase_bf_pipeline_manager):
 
     save_folder, config, manager = init_phase_bf_pipeline_manager
     manager.run()
 
-    store = zarr.open(os.path.join(save_folder, '2T_3P_16Z_128Y_256X_Kazansky_BF_1.zarr'))
-    array = store['Row_0']['Col_0']['Pos_000']['arr_0']
+    store = zarr.open(
+        os.path.join(save_folder, "2T_3P_16Z_128Y_256X_Kazansky_BF_1.zarr")
+    )
+    array = store["Row_0"]["Col_0"]["Pos_000"]["arr_0"]
+
+    assert store.attrs.asdict()["Config"] == config.yaml_dict
+    assert store["Row_0"]["Col_0"]["Pos_000"]
+    assert store["Row_0"]["Col_1"]["Pos_001"]
+    assert store["Row_0"]["Col_2"]["Pos_002"]
+    assert array.shape == (2, 1, 16, manager.data.height, manager.data.width)
 
-    assert (store.attrs.asdict()['Config'] == config.yaml_dict)
-    assert (store['Row_0']['Col_0']['Pos_000'])
-    assert (store['Row_0']['Col_1']['Pos_001'])
-    assert (store['Row_0']['Col_2']['Pos_002'])
-    assert (array.shape == (2, 1, 16, manager.data.height, manager.data.width))
 
 def test_3D_reconstruction(get_bf_data_dir, setup_data_save_folder):
 
     folder, bf_data = get_bf_data_dir
     save_folder = setup_data_save_folder
 
-    path_to_config = os.path.join(dirname(dirname(abspath(__file__))), 'test_configs/phase/config_phase_3D_pytest.yml')
-    config = ConfigReader(path_to_config, data_dir=bf_data, save_dir=save_folder)
+    path_to_config = os.path.join(
+        dirname(dirname(abspath(__file__))),
+        "test_configs/phase/config_phase_3D_pytest.yml",
+    )
+    config = ConfigReader(
+        path_to_config, data_dir=bf_data, save_dir=save_folder
+    )
 
     manager = PipelineManager(config)
-    assert(manager.pipeline.mode == '3D')
+    assert manager.pipeline.mode == "3D"
     manager.run()
 
     pos, t, z = 1, 0, 8
     data = manager.data.get_array(pos)
     recon = manager.pipeline.reconstructor
 
-    phase3D = reconstruct_phase3D(data[t, 0], recon, method=config.phase_denoiser_3D,
-                                  reg_re=config.Tik_reg_ph_3D, rho=config.rho_3D, lambda_re=config.TV_reg_ph_3D,
-                                  itr=config.itr_3D)
-
-    store = zarr.open(os.path.join(save_folder, '2T_3P_16Z_128Y_256X_Kazansky_BF_1.zarr'), 'r')
+    phase3D = reconstruct_phase3D(
+        data[t, 0],
+        recon,
+        method=config.phase_denoiser_3D,
+        reg_re=config.Tik_reg_ph_3D,
+        rho=config.rho_3D,
+        lambda_re=config.TV_reg_ph_3D,
+        itr=config.itr_3D,
+    )
+
+    store = zarr.open(
+        os.path.join(save_folder, "2T_3P_16Z_128Y_256X_Kazansky_BF_1.zarr"),
+        "r",
+    )
     # This may be bug, should be store['Row_0']['Col_1']['Pos_001']['arr_0']
-    array = store['Row_0']['Col_0']['Pos_001']['arr_0']
+    array = store["Row_0"]["Col_0"]["Pos_001"]["arr_0"]
 
     # Check Shape
-    assert(array.shape == (1, len(config.output_channels), 16, 128, 256))
+    assert array.shape == (1, len(config.output_channels), 16, 128, 256)
 
     # Check Phase
-    assert(np.sum(np.abs(phase3D[z] - array[0, 0, z]) ** 2) / np.sum(np.abs(phase3D[z])**2) < 0.1)
+    assert (
+        np.sum(np.abs(phase3D[z] - array[0, 0, z]) ** 2)
+        / np.sum(np.abs(phase3D[z]) ** 2)
+        < 0.1
+    )
+
 
 def test_2D_reconstruction(get_bf_data_dir, setup_data_save_folder):
 
     folder, bf_data = get_bf_data_dir
     save_folder = setup_data_save_folder
 
-    path_to_config = os.path.join(dirname(dirname(abspath(__file__))), 'test_configs/phase/config_phase_2D_pytest.yml')
-    config = ConfigReader(path_to_config, data_dir=bf_data, save_dir=save_folder)
+    path_to_config = os.path.join(
+        dirname(dirname(abspath(__file__))),
+        "test_configs/phase/config_phase_2D_pytest.yml",
+    )
+    config = ConfigReader(
+        path_to_config, data_dir=bf_data, save_dir=save_folder
+    )
 
     manager = PipelineManager(config)
-    assert(manager.pipeline.mode == '2D')
+    assert manager.pipeline.mode == "2D"
     manager.run()
 
     pos, t, z = 1, 0, manager.pipeline.focus_slice
     data = manager.data.get_array(pos)
     recon = manager.pipeline.reconstructor
 
-    phase2D = reconstruct_phase2D(data[t, 0], recon, method=config.phase_denoiser_2D,
-                                  reg_p=config.Tik_reg_ph_2D, rho=config.rho_2D, lambda_p=config.TV_reg_ph_2D,
-                                  itr=config.itr_2D)
-    store = zarr.open(os.path.join(save_folder, '2T_3P_16Z_128Y_256X_Kazansky_BF_1.zarr'), 'r')
+    phase2D = reconstruct_phase2D(
+        data[t, 0],
+        recon,
+        method=config.phase_denoiser_2D,
+        reg_p=config.Tik_reg_ph_2D,
+        rho=config.rho_2D,
+        lambda_p=config.TV_reg_ph_2D,
+        itr=config.itr_2D,
+    )
+    store = zarr.open(
+        os.path.join(save_folder, "2T_3P_16Z_128Y_256X_Kazansky_BF_1.zarr"),
+        "r",
+    )
     # This may be bug, should be store['Row_0']['Col_1']['Pos_001']['arr_0']
-    array = store['Row_0']['Col_0']['Pos_001']['arr_0']
+    array = store["Row_0"]["Col_0"]["Pos_001"]["arr_0"]
 
     # Check Shapes
-    assert(array.shape == (1, len(config.output_channels), 1, 128, 256))
+    assert array.shape == (1, len(config.output_channels), 1, 128, 256)
 
     # Check Phase
-    assert (np.sum(np.abs(phase2D - array[0, 0, 0]) ** 2) / np.sum(np.abs(phase2D)**2) < 0.1)
\ No newline at end of file
+    assert (
+        np.sum(np.abs(phase2D - array[0, 0, 0]) ** 2)
+        / np.sum(np.abs(phase2D) ** 2)
+        < 0.1
+    )
diff --git a/recOrder/tests/pipeline_tests/test_qlipp_pipeline.py b/recOrder/tests/pipeline_tests/test_qlipp_pipeline.py
index 159b035b..e4d579d7 100644
--- a/recOrder/tests/pipeline_tests/test_qlipp_pipeline.py
+++ b/recOrder/tests/pipeline_tests/test_qlipp_pipeline.py
@@ -3,31 +3,54 @@
 from recOrder.pipelines.pipeline_manager import PipelineManager
 from recOrder.pipelines.qlipp_pipeline import QLIPP
 from waveorder.io.writer import WaveorderWriter
-from recOrder.compute.qlipp_compute import reconstruct_qlipp_stokes, reconstruct_qlipp_birefringence, \
-    reconstruct_phase3D, reconstruct_phase2D
+from recOrder.compute.qlipp_compute import (
+    reconstruct_qlipp_stokes,
+    reconstruct_qlipp_birefringence,
+    reconstruct_phase3D,
+    reconstruct_phase2D,
+)
 from os.path import dirname, abspath
 import numpy as np
 import os
 import subprocess
 import zarr
 
+
 def test_cli_config(setup_test_data, setup_data_save_folder):
     file_path = os.path.dirname(os.path.dirname(__file__))
-    path_to_config = os.path.abspath(os.path.join(file_path, './test_configs/qlipp/config_qlipp_full_pytest.yml'))
-    zarr_data = os.path.join(setup_test_data, '2022_08_04_recOrder_pytest_20x_04NA_zarr', '2T_3P_16Z_128Y_256X_Kazansky.zarr')
-
-    cmd_string = ' '.join(['recOrder.reconstruct', '--config', path_to_config, '--data_dir', zarr_data,
-                           '--save_dir', setup_data_save_folder])
+    path_to_config = os.path.abspath(
+        os.path.join(
+            file_path, "./test_configs/qlipp/config_qlipp_full_pytest.yml"
+        )
+    )
+    zarr_data = os.path.join(
+        setup_test_data,
+        "2022_08_04_recOrder_pytest_20x_04NA_zarr",
+        "2T_3P_16Z_128Y_256X_Kazansky.zarr",
+    )
+
+    cmd_string = " ".join(
+        [
+            "recOrder.reconstruct",
+            "--config",
+            path_to_config,
+            "--data_dir",
+            zarr_data,
+            "--save_dir",
+            setup_data_save_folder,
+        ]
+    )
 
     result = subprocess.run(cmd_string, shell=True)
-    assert(result.returncode == 0)
+    assert result.returncode == 0
+
 
 def test_pipeline_manager_initiate(init_qlipp_pipeline_manager):
 
     save_folder, config, manager = init_qlipp_pipeline_manager
 
-    assert(manager.config is not None)
-    assert(manager.data is not None)
+    assert manager.config is not None
+    assert manager.data is not None
 
     # check to make sure position mapping is correct
     list_p = []
@@ -36,94 +59,171 @@ def test_pipeline_manager_initiate(init_qlipp_pipeline_manager):
             list_p.append(i[0])
     list_p.sort()
     for idx, p in enumerate(list_p):
-        assert(manager.indices_map[p] == idx)
+        assert manager.indices_map[p] == idx
+
+    assert manager.data.get_num_positions() * manager.data.frames == len(
+        manager.pt_set
+    )
+    assert manager.pipeline is not None
+    assert isinstance(manager.pipeline, QLIPP)
 
-    assert(manager.data.get_num_positions()*manager.data.frames == len(manager.pt_set))
-    assert(manager.pipeline is not None)
-    assert(isinstance(manager.pipeline, QLIPP))
 
 def test_qlipp_pipeline_initiate(init_qlipp_pipeline_manager):
 
     save_folder, config, manager = init_qlipp_pipeline_manager
 
     pipeline = manager.pipeline
-    assert(pipeline.config == manager.config)
-    assert(pipeline.data == manager.data)
-    assert(pipeline.t == manager.num_t)
-    assert(isinstance(pipeline.writer, WaveorderWriter))
-    assert(pipeline.mode == '3D')
-    assert(pipeline.no_birefringence == False)
-    assert(pipeline.slices == manager.data.slices)
-    assert(pipeline.img_dim == (manager.data.height, manager.data.width, manager.data.slices))
-    assert(pipeline.chan_names == manager.data.channel_names)
-    assert(isinstance(pipeline.calib_meta, MetadataReader))
-    assert(pipeline.bg_path == manager.config.background)
-
-    assert(pipeline.s0_idx == 0)
-    assert(pipeline.s1_idx == 1)
-    assert(pipeline.s2_idx == 2)
-    assert(pipeline.s3_idx == 3)
-    assert(pipeline.data_shape == (manager.data.frames, manager.data.channels,
-                                   manager.data.slices, manager.data.height, manager.data.width))
-    assert(pipeline.chunk_size == (1, 1, 1, manager.data.height, manager.data.width))
-    assert(isinstance(pipeline.writer, WaveorderWriter))
-    assert(pipeline.reconstructor is not None)
-    assert(pipeline.bg_stokes is not None)
+    assert pipeline.config == manager.config
+    assert pipeline.data == manager.data
+    assert pipeline.t == manager.num_t
+    assert isinstance(pipeline.writer, WaveorderWriter)
+    assert pipeline.mode == "3D"
+    assert pipeline.no_birefringence == False
+    assert pipeline.slices == manager.data.slices
+    assert pipeline.img_dim == (
+        manager.data.height,
+        manager.data.width,
+        manager.data.slices,
+    )
+    assert pipeline.chan_names == manager.data.channel_names
+    assert isinstance(pipeline.calib_meta, MetadataReader)
+    assert pipeline.bg_path == manager.config.background
+
+    assert pipeline.s0_idx == 0
+    assert pipeline.s1_idx == 1
+    assert pipeline.s2_idx == 2
+    assert pipeline.s3_idx == 3
+    assert pipeline.data_shape == (
+        manager.data.frames,
+        manager.data.channels,
+        manager.data.slices,
+        manager.data.height,
+        manager.data.width,
+    )
+    assert pipeline.chunk_size == (
+        1,
+        1,
+        1,
+        manager.data.height,
+        manager.data.width,
+    )
+    assert isinstance(pipeline.writer, WaveorderWriter)
+    assert pipeline.reconstructor is not None
+    assert pipeline.bg_stokes is not None
+
 
 def test_pipeline_manager_run(init_qlipp_pipeline_manager):
 
     save_folder, config, manager = init_qlipp_pipeline_manager
     manager.run()
 
-    store = zarr.open(os.path.join(save_folder, '2T_3P_16Z_128Y_256X_Kazansky.zarr'))
-    array = store['Row_0']['Col_0']['Pos_000']['arr_0']
+    store = zarr.open(
+        os.path.join(save_folder, "2T_3P_16Z_128Y_256X_Kazansky.zarr")
+    )
+    array = store["Row_0"]["Col_0"]["Pos_000"]["arr_0"]
+
+    assert store.attrs.asdict()["Config"] == config.yaml_dict
+    assert store["Row_0"]["Col_0"]["Pos_000"]
+    assert store["Row_0"]["Col_1"]["Pos_001"]
+    assert store["Row_0"]["Col_2"]["Pos_002"]
+    assert array.shape == (2, 4, 16, manager.data.height, manager.data.width)
 
-    assert(store.attrs.asdict()['Config'] == config.yaml_dict)
-    assert(store['Row_0']['Col_0']['Pos_000'])
-    assert(store['Row_0']['Col_1']['Pos_001'])
-    assert(store['Row_0']['Col_2']['Pos_002'])
-    assert(array.shape == (2, 4, 16, manager.data.height, manager.data.width))
 
 def test_3D_reconstruction(get_zarr_data_dir, setup_data_save_folder):
 
     folder, zarr_data = get_zarr_data_dir
     save_folder = setup_data_save_folder
 
-    path_to_config = os.path.join(dirname(dirname(abspath(__file__))), 'test_configs/qlipp/config_qlipp_full_recon_pytest.yml')
-    config = ConfigReader(path_to_config, data_dir=zarr_data, save_dir=save_folder)
+    path_to_config = os.path.join(
+        dirname(dirname(abspath(__file__))),
+        "test_configs/qlipp/config_qlipp_full_recon_pytest.yml",
+    )
+    config = ConfigReader(
+        path_to_config, data_dir=zarr_data, save_dir=save_folder
+    )
 
     manager = PipelineManager(config)
-    assert(manager.pipeline.mode == '3D')
+    assert manager.pipeline.mode == "3D"
     manager.run()
 
     pos, t, z = 1, 0, 8
     data = manager.data.get_array(pos)
     recon = manager.pipeline.reconstructor
 
-    stokes = reconstruct_qlipp_stokes(data[t], recon, manager.pipeline.bg_stokes)
+    stokes = reconstruct_qlipp_stokes(
+        data[t], recon, manager.pipeline.bg_stokes
+    )
     birefringence = reconstruct_qlipp_birefringence(stokes, recon)
-    phase3D = reconstruct_phase3D(stokes[0], recon, method=config.phase_denoiser_3D, reg_re=config.Tik_reg_ph_3D,
-                                  rho=config.rho_3D, lambda_re=config.TV_reg_ph_3D, itr=config.itr_3D)
-    store = zarr.open(os.path.join(save_folder, '2T_3P_16Z_128Y_256X_Kazansky.zarr'))
-    array = store['Row_0']['Col_1']['Pos_001']['arr_0']
+    phase3D = reconstruct_phase3D(
+        stokes[0],
+        recon,
+        method=config.phase_denoiser_3D,
+        reg_re=config.Tik_reg_ph_3D,
+        rho=config.rho_3D,
+        lambda_re=config.TV_reg_ph_3D,
+        itr=config.itr_3D,
+    )
+    store = zarr.open(
+        os.path.join(save_folder, "2T_3P_16Z_128Y_256X_Kazansky.zarr")
+    )
+    array = store["Row_0"]["Col_1"]["Pos_001"]["arr_0"]
 
     # Check Shape
-    assert(array.shape == (1, len(config.output_channels), 16, 128, 256))
+    assert array.shape == (1, len(config.output_channels), 16, 128, 256)
 
     # Check Stokes
-    assert(np.sum(np.abs(stokes[0, z, :, :] - array[0, 4, z]) ** 2) / np.sum(np.abs(stokes[0, z, :, :])**2) < 0.1)
-    assert(np.sum(np.abs(stokes[1, z, :, :] - array[0, 5, z]) ** 2) / np.sum(np.abs(stokes[1, z, :, :])**2) < 0.1)
-    assert(np.sum(np.abs(stokes[2, z, :, :] - array[0, 6, z]) ** 2) / np.sum(np.abs(stokes[2, z, :, :])**2) < 0.1)
-    assert(np.sum(np.abs(stokes[3, z, :, :] - array[0, 7, z]) ** 2) / np.sum(np.abs(stokes[3, z, :, :])**2) < 0.1)
+    assert (
+        np.sum(np.abs(stokes[0, z, :, :] - array[0, 4, z]) ** 2)
+        / np.sum(np.abs(stokes[0, z, :, :]) ** 2)
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[1, z, :, :] - array[0, 5, z]) ** 2)
+        / np.sum(np.abs(stokes[1, z, :, :]) ** 2)
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[2, z, :, :] - array[0, 6, z]) ** 2)
+        / np.sum(np.abs(stokes[2, z, :, :]) ** 2)
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[3, z, :, :] - array[0, 7, z]) ** 2)
+        / np.sum(np.abs(stokes[3, z, :, :]) ** 2)
+        < 0.1
+    )
 
     # Check Birefringence
-    assert(np.sum(np.abs((birefringence[0, z]/(2 * np.pi)*config.wavelength) - array[0, 0, z]) ** 2)
-           / np.sum(np.abs(birefringence[0, z]/(2 * np.pi)*config.wavelength)**2) < 0.1)
-    assert (np.sum(np.abs(birefringence[1, z] - array[0, 1, z]) ** 2) / np.sum(np.abs(birefringence[1, z])**2) < 0.1)
-    assert (np.sum(np.abs(birefringence[2, z] - array[0, 2, z]) ** 2) / np.sum(np.abs(birefringence[2, z])**2) < 0.1)
+    assert (
+        np.sum(
+            np.abs(
+                (birefringence[0, z] / (2 * np.pi) * config.wavelength)
+                - array[0, 0, z]
+            )
+            ** 2
+        )
+        / np.sum(
+            np.abs(birefringence[0, z] / (2 * np.pi) * config.wavelength) ** 2
+        )
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(birefringence[1, z] - array[0, 1, z]) ** 2)
+        / np.sum(np.abs(birefringence[1, z]) ** 2)
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(birefringence[2, z] - array[0, 2, z]) ** 2)
+        / np.sum(np.abs(birefringence[2, z]) ** 2)
+        < 0.1
+    )
 
     # Check Phase
-    assert (np.sum(np.abs(phase3D[z] - array[0, 3, z]) ** 2) / np.sum(np.abs(phase3D[z])**2) < 0.1)
+    assert (
+        np.sum(np.abs(phase3D[z] - array[0, 3, z]) ** 2)
+        / np.sum(np.abs(phase3D[z]) ** 2)
+        < 0.1
+    )
 
 
 def test_2D_reconstruction(get_zarr_data_dir, setup_data_save_folder):
@@ -131,40 +231,95 @@ def test_2D_reconstruction(get_zarr_data_dir, setup_data_save_folder):
     folder, zarr_data = get_zarr_data_dir
     save_folder = setup_data_save_folder
 
-    path_to_config = os.path.join(dirname(dirname(abspath(__file__))), 'test_configs/qlipp/config_qlipp_2D_pytest.yml')
-    config = ConfigReader(path_to_config, data_dir=zarr_data, save_dir=save_folder)
+    path_to_config = os.path.join(
+        dirname(dirname(abspath(__file__))),
+        "test_configs/qlipp/config_qlipp_2D_pytest.yml",
+    )
+    config = ConfigReader(
+        path_to_config, data_dir=zarr_data, save_dir=save_folder
+    )
 
     manager = PipelineManager(config)
-    assert(manager.pipeline.mode == '2D')
+    assert manager.pipeline.mode == "2D"
     manager.run()
 
     pos, t, z = 1, 0, manager.pipeline.focus_slice
     data = manager.data.get_array(pos)
     recon = manager.pipeline.reconstructor
 
-    stokes = reconstruct_qlipp_stokes(data[t], recon, manager.pipeline.bg_stokes)
+    stokes = reconstruct_qlipp_stokes(
+        data[t], recon, manager.pipeline.bg_stokes
+    )
     birefringence = reconstruct_qlipp_birefringence(stokes[:, z, :, :], recon)
-    phase2D = reconstruct_phase2D(stokes[0], recon, method=config.phase_denoiser_2D, reg_p=config.Tik_reg_ph_2D,
-                                  rho=config.rho_2D, lambda_p=config.TV_reg_ph_2D, itr=config.itr_2D)
-    store = zarr.open(os.path.join(save_folder, '2T_3P_16Z_128Y_256X_Kazansky.zarr'))
-    array = store['Row_0']['Col_1']['Pos_001']['arr_0']
+    phase2D = reconstruct_phase2D(
+        stokes[0],
+        recon,
+        method=config.phase_denoiser_2D,
+        reg_p=config.Tik_reg_ph_2D,
+        rho=config.rho_2D,
+        lambda_p=config.TV_reg_ph_2D,
+        itr=config.itr_2D,
+    )
+    store = zarr.open(
+        os.path.join(save_folder, "2T_3P_16Z_128Y_256X_Kazansky.zarr")
+    )
+    array = store["Row_0"]["Col_1"]["Pos_001"]["arr_0"]
 
     # Check Shapes
-    assert(array.shape == (1, len(config.output_channels), 1, 128, 256))
+    assert array.shape == (1, len(config.output_channels), 1, 128, 256)
 
     # Check Stokes
-    assert(np.sum(np.abs(stokes[0, z, :, :] - array[0, 4, 0]) ** 2) / np.sum(np.abs(stokes[0, z, :, :]))**2 < 0.1)
-    assert(np.sum(np.abs(stokes[1, z, :, :] - array[0, 5, 0]) ** 2) / np.sum(np.abs(stokes[1, z, :, :]))**2 < 0.1)
-    assert(np.sum(np.abs(stokes[2, z, :, :] - array[0, 6, 0]) ** 2) / np.sum(np.abs(stokes[2, z, :, :]))**2 < 0.1)
-    assert(np.sum(np.abs(stokes[3, z, :, :] - array[0, 7, 0]) ** 2) / np.sum(np.abs(stokes[3, z, :, :]))**2 < 0.1)
+    assert (
+        np.sum(np.abs(stokes[0, z, :, :] - array[0, 4, 0]) ** 2)
+        / np.sum(np.abs(stokes[0, z, :, :])) ** 2
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[1, z, :, :] - array[0, 5, 0]) ** 2)
+        / np.sum(np.abs(stokes[1, z, :, :])) ** 2
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[2, z, :, :] - array[0, 6, 0]) ** 2)
+        / np.sum(np.abs(stokes[2, z, :, :])) ** 2
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[3, z, :, :] - array[0, 7, 0]) ** 2)
+        / np.sum(np.abs(stokes[3, z, :, :])) ** 2
+        < 0.1
+    )
 
     # Check Birefringence
 
-    assert(np.sum(np.abs((birefringence[0]/(2 * np.pi)*config.wavelength) - array[0, 0, 0]) ** 2)
-           / np.sum(np.abs(birefringence[0]/(2 * np.pi)*config.wavelength)**2) < 0.1)
-    assert (np.sum(np.abs(birefringence[1] - array[0, 1, 0]) ** 2) / np.sum(np.abs(birefringence[1])**2) < 0.1)
-    assert (np.sum(np.abs(birefringence[2] - array[0, 2, 0]) ** 2) / np.sum(np.abs(birefringence[2])**2) < 0.1)
+    assert (
+        np.sum(
+            np.abs(
+                (birefringence[0] / (2 * np.pi) * config.wavelength)
+                - array[0, 0, 0]
+            )
+            ** 2
+        )
+        / np.sum(
+            np.abs(birefringence[0] / (2 * np.pi) * config.wavelength) ** 2
+        )
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(birefringence[1] - array[0, 1, 0]) ** 2)
+        / np.sum(np.abs(birefringence[1]) ** 2)
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(birefringence[2] - array[0, 2, 0]) ** 2)
+        / np.sum(np.abs(birefringence[2]) ** 2)
+        < 0.1
+    )
 
     # Check Phase
-    assert (np.sum(np.abs(phase2D - array[0, 3, 0]) ** 2) / np.sum(np.abs(phase2D)**2) < 0.1)
-    #TODO: Add tests/test data for 5 state reconstruction?
\ No newline at end of file
+    assert (
+        np.sum(np.abs(phase2D - array[0, 3, 0]) ** 2)
+        / np.sum(np.abs(phase2D) ** 2)
+        < 0.1
+    )
+    # TODO: Add tests/test data for 5 state reconstruction?
diff --git a/recOrder/tests/pipeline_tests/test_qlipp_pipeline_tiff.py b/recOrder/tests/pipeline_tests/test_qlipp_pipeline_tiff.py
index ea6f3f75..a2ea898f 100644
--- a/recOrder/tests/pipeline_tests/test_qlipp_pipeline_tiff.py
+++ b/recOrder/tests/pipeline_tests/test_qlipp_pipeline_tiff.py
@@ -3,19 +3,24 @@
 from recOrder.pipelines.pipeline_manager import PipelineManager
 from recOrder.pipelines.qlipp_pipeline import QLIPP
 from waveorder.io.writer import WaveorderWriter
-from recOrder.compute.qlipp_compute import reconstruct_qlipp_stokes, reconstruct_qlipp_birefringence, \
-    reconstruct_phase3D, reconstruct_phase2D
+from recOrder.compute.qlipp_compute import (
+    reconstruct_qlipp_stokes,
+    reconstruct_qlipp_birefringence,
+    reconstruct_phase3D,
+    reconstruct_phase2D,
+)
 from os.path import dirname, abspath
 import numpy as np
 import os
 import zarr
 
+
 def test_pipeline_manager_initiate(init_qlipp_tiff_pipeline_manager):
 
     save_folder, config, manager = init_qlipp_tiff_pipeline_manager
 
-    assert(manager.config is not None)
-    assert(manager.data is not None)
+    assert manager.config is not None
+    assert manager.data is not None
 
     # check to make sure position mapping is correct
     list_p = []
@@ -24,94 +29,171 @@ def test_pipeline_manager_initiate(init_qlipp_tiff_pipeline_manager):
             list_p.append(i[0])
     list_p.sort()
     for idx, p in enumerate(list_p):
-        assert(manager.indices_map[p] == idx)
+        assert manager.indices_map[p] == idx
+
+    assert manager.data.get_num_positions() * manager.data.frames == len(
+        manager.pt_set
+    )
+    assert manager.pipeline is not None
+    assert isinstance(manager.pipeline, QLIPP)
 
-    assert(manager.data.get_num_positions()*manager.data.frames == len(manager.pt_set))
-    assert(manager.pipeline is not None)
-    assert(isinstance(manager.pipeline, QLIPP))
 
 def test_qlipp_pipeline_initiate(init_qlipp_tiff_pipeline_manager):
 
     save_folder, config, manager = init_qlipp_tiff_pipeline_manager
 
     pipeline = manager.pipeline
-    assert(pipeline.config == manager.config)
-    assert(pipeline.data == manager.data)
-    assert(pipeline.t == manager.num_t)
-    assert(isinstance(pipeline.writer, WaveorderWriter))
-    assert(pipeline.mode == '3D')
-    assert(pipeline.no_birefringence == False)
-    assert(pipeline.slices == manager.data.slices)
-    assert(pipeline.img_dim == (manager.data.height, manager.data.width, manager.data.slices))
-    assert(pipeline.chan_names == manager.data.channel_names)
-    assert(isinstance(pipeline.calib_meta, MetadataReader))
-    assert(pipeline.bg_path == manager.config.background)
-
-    assert(pipeline.s0_idx == 0)
-    assert(pipeline.s1_idx == 1)
-    assert(pipeline.s2_idx == 2)
-    assert(pipeline.s3_idx == 3)
-    assert(pipeline.data_shape == (manager.data.frames, manager.data.channels,
-                                   manager.data.slices, manager.data.height, manager.data.width))
-    assert(pipeline.chunk_size == (1, 1, 1, manager.data.height, manager.data.width))
-    assert(isinstance(pipeline.writer, WaveorderWriter))
-    assert(pipeline.reconstructor is not None)
-    assert(pipeline.bg_stokes is not None)
+    assert pipeline.config == manager.config
+    assert pipeline.data == manager.data
+    assert pipeline.t == manager.num_t
+    assert isinstance(pipeline.writer, WaveorderWriter)
+    assert pipeline.mode == "3D"
+    assert pipeline.no_birefringence == False
+    assert pipeline.slices == manager.data.slices
+    assert pipeline.img_dim == (
+        manager.data.height,
+        manager.data.width,
+        manager.data.slices,
+    )
+    assert pipeline.chan_names == manager.data.channel_names
+    assert isinstance(pipeline.calib_meta, MetadataReader)
+    assert pipeline.bg_path == manager.config.background
+
+    assert pipeline.s0_idx == 0
+    assert pipeline.s1_idx == 1
+    assert pipeline.s2_idx == 2
+    assert pipeline.s3_idx == 3
+    assert pipeline.data_shape == (
+        manager.data.frames,
+        manager.data.channels,
+        manager.data.slices,
+        manager.data.height,
+        manager.data.width,
+    )
+    assert pipeline.chunk_size == (
+        1,
+        1,
+        1,
+        manager.data.height,
+        manager.data.width,
+    )
+    assert isinstance(pipeline.writer, WaveorderWriter)
+    assert pipeline.reconstructor is not None
+    assert pipeline.bg_stokes is not None
+
 
 def test_pipeline_manager_run(init_qlipp_tiff_pipeline_manager):
 
     save_folder, config, manager = init_qlipp_tiff_pipeline_manager
     manager.run()
 
-    store = zarr.open(os.path.join(save_folder, '2T_3P_16Z_128Y_256X_Kazansky_1.zarr'), 'r')
-    array = store['Row_0']['Col_0']['Pos_000']['arr_0']
+    store = zarr.open(
+        os.path.join(save_folder, "2T_3P_16Z_128Y_256X_Kazansky_1.zarr"), "r"
+    )
+    array = store["Row_0"]["Col_0"]["Pos_000"]["arr_0"]
+
+    assert store.attrs.asdict()["Config"] == config.yaml_dict
+    assert store["Row_0"]["Col_0"]["Pos_000"]
+    assert store["Row_0"]["Col_1"]["Pos_001"]
+    assert store["Row_0"]["Col_2"]["Pos_002"]
+    assert array.shape == (2, 4, 16, manager.data.height, manager.data.width)
 
-    assert(store.attrs.asdict()['Config'] == config.yaml_dict)
-    assert(store['Row_0']['Col_0']['Pos_000'])
-    assert(store['Row_0']['Col_1']['Pos_001'])
-    assert(store['Row_0']['Col_2']['Pos_002'])
-    assert(array.shape == (2, 4, 16, manager.data.height, manager.data.width))
 
 def test_3D_reconstruction(get_ometiff_data_dir, setup_data_save_folder):
 
     folder, ometiff_data = get_ometiff_data_dir
     save_folder = setup_data_save_folder
 
-    path_to_config = os.path.join(dirname(dirname(abspath(__file__))), 'test_configs/qlipp/config_qlipp_full_recon_pytest_tiff.yml')
-    config = ConfigReader(path_to_config, data_dir=ometiff_data, save_dir=save_folder)
+    path_to_config = os.path.join(
+        dirname(dirname(abspath(__file__))),
+        "test_configs/qlipp/config_qlipp_full_recon_pytest_tiff.yml",
+    )
+    config = ConfigReader(
+        path_to_config, data_dir=ometiff_data, save_dir=save_folder
+    )
 
     manager = PipelineManager(config)
-    assert(manager.pipeline.mode == '3D')
+    assert manager.pipeline.mode == "3D"
     manager.run()
 
     pos, t, z = 1, 0, 8
     data = manager.data.get_array(pos)
     recon = manager.pipeline.reconstructor
 
-    stokes = reconstruct_qlipp_stokes(data[t], recon, manager.pipeline.bg_stokes)
+    stokes = reconstruct_qlipp_stokes(
+        data[t], recon, manager.pipeline.bg_stokes
+    )
     birefringence = reconstruct_qlipp_birefringence(stokes, recon)
-    phase3D = reconstruct_phase3D(stokes[0], recon, method=config.phase_denoiser_3D, reg_re=config.Tik_reg_ph_3D,
-                                  rho=config.rho_3D, lambda_re=config.TV_reg_ph_3D, itr=config.itr_3D)
-    store = zarr.open(os.path.join(save_folder, '2T_3P_16Z_128Y_256X_Kazansky_1.zarr'), 'r')
-    array = store['Row_0']['Col_0']['Pos_001']['arr_0']
+    phase3D = reconstruct_phase3D(
+        stokes[0],
+        recon,
+        method=config.phase_denoiser_3D,
+        reg_re=config.Tik_reg_ph_3D,
+        rho=config.rho_3D,
+        lambda_re=config.TV_reg_ph_3D,
+        itr=config.itr_3D,
+    )
+    store = zarr.open(
+        os.path.join(save_folder, "2T_3P_16Z_128Y_256X_Kazansky_1.zarr"), "r"
+    )
+    array = store["Row_0"]["Col_0"]["Pos_001"]["arr_0"]
 
     # Check Shape
-    assert(array.shape == (1, len(config.output_channels), 16, 128, 256))
+    assert array.shape == (1, len(config.output_channels), 16, 128, 256)
 
     # Check Stokes
-    assert(np.sum(np.abs(stokes[0, z, :, :] - array[0, 4, z]) ** 2) / np.sum(np.abs(stokes[0, z, :, :])**2) < 0.1)
-    assert(np.sum(np.abs(stokes[1, z, :, :] - array[0, 5, z]) ** 2) / np.sum(np.abs(stokes[1, z, :, :])**2) < 0.1)
-    assert(np.sum(np.abs(stokes[2, z, :, :] - array[0, 6, z]) ** 2) / np.sum(np.abs(stokes[2, z, :, :])**2) < 0.1)
-    assert(np.sum(np.abs(stokes[3, z, :, :] - array[0, 7, z]) ** 2) / np.sum(np.abs(stokes[3, z, :, :])**2) < 0.1)
+    assert (
+        np.sum(np.abs(stokes[0, z, :, :] - array[0, 4, z]) ** 2)
+        / np.sum(np.abs(stokes[0, z, :, :]) ** 2)
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[1, z, :, :] - array[0, 5, z]) ** 2)
+        / np.sum(np.abs(stokes[1, z, :, :]) ** 2)
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[2, z, :, :] - array[0, 6, z]) ** 2)
+        / np.sum(np.abs(stokes[2, z, :, :]) ** 2)
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[3, z, :, :] - array[0, 7, z]) ** 2)
+        / np.sum(np.abs(stokes[3, z, :, :]) ** 2)
+        < 0.1
+    )
 
     # Check Birefringence
-    assert(np.sum(np.abs((birefringence[0, z]/(2 * np.pi)*config.wavelength) - array[0, 0, z]) ** 2)
-           / np.sum(np.abs(birefringence[0, z]/(2 * np.pi)*config.wavelength)**2) < 0.1)
-    assert (np.sum(np.abs(birefringence[1, z] - array[0, 1, z]) ** 2) / np.sum(np.abs(birefringence[1, z])**2) < 0.1)
-    assert (np.sum(np.abs(birefringence[2, z] - array[0, 2, z]) ** 2) / np.sum(np.abs(birefringence[2, z])**2) < 0.1)
+    assert (
+        np.sum(
+            np.abs(
+                (birefringence[0, z] / (2 * np.pi) * config.wavelength)
+                - array[0, 0, z]
+            )
+            ** 2
+        )
+        / np.sum(
+            np.abs(birefringence[0, z] / (2 * np.pi) * config.wavelength) ** 2
+        )
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(birefringence[1, z] - array[0, 1, z]) ** 2)
+        / np.sum(np.abs(birefringence[1, z]) ** 2)
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(birefringence[2, z] - array[0, 2, z]) ** 2)
+        / np.sum(np.abs(birefringence[2, z]) ** 2)
+        < 0.1
+    )
 
     # Check Phase
-    assert (np.sum(np.abs(phase3D[z] - array[0, 3, z]) ** 2) / np.sum(np.abs(phase3D[z])**2) < 0.1)
+    assert (
+        np.sum(np.abs(phase3D[z] - array[0, 3, z]) ** 2)
+        / np.sum(np.abs(phase3D[z]) ** 2)
+        < 0.1
+    )
 
 
 def test_2D_reconstruction(get_ometiff_data_dir, setup_data_save_folder):
@@ -119,39 +201,94 @@ def test_2D_reconstruction(get_ometiff_data_dir, setup_data_save_folder):
     folder, ometiff_data = get_ometiff_data_dir
     save_folder = setup_data_save_folder
 
-    path_to_config = os.path.join(dirname(dirname(abspath(__file__))), 'test_configs/qlipp/config_qlipp_2D_pytest_tiff.yml')
-    config = ConfigReader(path_to_config, data_dir=ometiff_data, save_dir=save_folder)
+    path_to_config = os.path.join(
+        dirname(dirname(abspath(__file__))),
+        "test_configs/qlipp/config_qlipp_2D_pytest_tiff.yml",
+    )
+    config = ConfigReader(
+        path_to_config, data_dir=ometiff_data, save_dir=save_folder
+    )
 
     manager = PipelineManager(config)
-    assert(manager.pipeline.mode == '2D')
+    assert manager.pipeline.mode == "2D"
     manager.run()
 
     pos, t, z = 1, 0, manager.pipeline.focus_slice
     data = manager.data.get_array(pos)
     recon = manager.pipeline.reconstructor
 
-    stokes = reconstruct_qlipp_stokes(data[t], recon, manager.pipeline.bg_stokes)
+    stokes = reconstruct_qlipp_stokes(
+        data[t], recon, manager.pipeline.bg_stokes
+    )
     birefringence = reconstruct_qlipp_birefringence(stokes[:, z, :, :], recon)
-    phase2D = reconstruct_phase2D(stokes[0], recon, method=config.phase_denoiser_2D, reg_p=config.Tik_reg_ph_2D,
-                                  rho=config.rho_2D, lambda_p=config.TV_reg_ph_2D, itr=config.itr_2D)
-    store = zarr.open(os.path.join(save_folder, '2T_3P_16Z_128Y_256X_Kazansky_1.zarr'), 'r')
-    array = store['Row_0']['Col_0']['Pos_001']['arr_0']
+    phase2D = reconstruct_phase2D(
+        stokes[0],
+        recon,
+        method=config.phase_denoiser_2D,
+        reg_p=config.Tik_reg_ph_2D,
+        rho=config.rho_2D,
+        lambda_p=config.TV_reg_ph_2D,
+        itr=config.itr_2D,
+    )
+    store = zarr.open(
+        os.path.join(save_folder, "2T_3P_16Z_128Y_256X_Kazansky_1.zarr"), "r"
+    )
+    array = store["Row_0"]["Col_0"]["Pos_001"]["arr_0"]
 
     # Check Shapes
-    assert(array.shape == (1, len(config.output_channels), 1, 128, 256))
+    assert array.shape == (1, len(config.output_channels), 1, 128, 256)
 
     # Check Stokes
-    assert(np.sum(np.abs(stokes[0, z, :, :] - array[0, 4, 0]) ** 2) / np.sum(np.abs(stokes[0, z, :, :]))**2 < 0.1)
-    assert(np.sum(np.abs(stokes[1, z, :, :] - array[0, 5, 0]) ** 2) / np.sum(np.abs(stokes[1, z, :, :]))**2 < 0.1)
-    assert(np.sum(np.abs(stokes[2, z, :, :] - array[0, 6, 0]) ** 2) / np.sum(np.abs(stokes[2, z, :, :]))**2 < 0.1)
-    assert(np.sum(np.abs(stokes[3, z, :, :] - array[0, 7, 0]) ** 2) / np.sum(np.abs(stokes[3, z, :, :]))**2 < 0.1)
+    assert (
+        np.sum(np.abs(stokes[0, z, :, :] - array[0, 4, 0]) ** 2)
+        / np.sum(np.abs(stokes[0, z, :, :])) ** 2
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[1, z, :, :] - array[0, 5, 0]) ** 2)
+        / np.sum(np.abs(stokes[1, z, :, :])) ** 2
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[2, z, :, :] - array[0, 6, 0]) ** 2)
+        / np.sum(np.abs(stokes[2, z, :, :])) ** 2
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(stokes[3, z, :, :] - array[0, 7, 0]) ** 2)
+        / np.sum(np.abs(stokes[3, z, :, :])) ** 2
+        < 0.1
+    )
 
     # Check Birefringence
 
-    assert(np.sum(np.abs((birefringence[0]/(2 * np.pi)*config.wavelength) - array[0, 0, 0]) ** 2)
-           / np.sum(np.abs(birefringence[0]/(2 * np.pi)*config.wavelength)**2) < 0.1)
-    assert (np.sum(np.abs(birefringence[1] - array[0, 1, 0]) ** 2) / np.sum(np.abs(birefringence[1])**2) < 0.1)
-    assert (np.sum(np.abs(birefringence[2] - array[0, 2, 0]) ** 2) / np.sum(np.abs(birefringence[2])**2) < 0.1)
+    assert (
+        np.sum(
+            np.abs(
+                (birefringence[0] / (2 * np.pi) * config.wavelength)
+                - array[0, 0, 0]
+            )
+            ** 2
+        )
+        / np.sum(
+            np.abs(birefringence[0] / (2 * np.pi) * config.wavelength) ** 2
+        )
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(birefringence[1] - array[0, 1, 0]) ** 2)
+        / np.sum(np.abs(birefringence[1]) ** 2)
+        < 0.1
+    )
+    assert (
+        np.sum(np.abs(birefringence[2] - array[0, 2, 0]) ** 2)
+        / np.sum(np.abs(birefringence[2]) ** 2)
+        < 0.1
+    )
 
     # Check Phase
-    assert (np.sum(np.abs(phase2D - array[0, 3, 0]) ** 2) / np.sum(np.abs(phase2D)**2) < 0.1)
\ No newline at end of file
+    assert (
+        np.sum(np.abs(phase2D - array[0, 3, 0]) ** 2)
+        / np.sum(np.abs(phase2D) ** 2)
+        < 0.1
+    )
diff --git a/recOrder/tests/reader_tests/test_reader.py b/recOrder/tests/reader_tests/test_reader.py
index f1af9a72..c78d3ad0 100644
--- a/recOrder/tests/reader_tests/test_reader.py
+++ b/recOrder/tests/reader_tests/test_reader.py
@@ -1,14 +1,20 @@
-from recOrder.io._reader import napari_get_reader, ome_zarr_reader, ome_tif_reader
+from recOrder.io._reader import (
+    napari_get_reader,
+    ome_zarr_reader,
+    ome_tif_reader,
+)
 import os
 from os.path import dirname, abspath
 import yaml
 
+
 def test_napari_get_reader(get_ometiff_data_dir, get_zarr_data_dir):
 
     _, ometiff_data = get_ometiff_data_dir
     _, zarr_data = get_zarr_data_dir
-    assert(napari_get_reader(ometiff_data).__name__ == 'ome_tif_reader')
-    assert(napari_get_reader(zarr_data).__name__ == 'ome_zarr_reader')
+    assert napari_get_reader(ometiff_data).__name__ == "ome_tif_reader"
+    assert napari_get_reader(zarr_data).__name__ == "ome_zarr_reader"
+
 
 def test_readers(get_ometiff_data_dir, get_zarr_data_dir):
 
@@ -19,5 +25,5 @@ def test_readers(get_ometiff_data_dir, get_zarr_data_dir):
     data_from_zarr = ome_zarr_reader(zarr_data)
 
     for data in [data_from_ome, data_from_zarr]:
-        assert(len(data) == 3)
-        assert(data[0][0].shape == (2, 4, 16, 128, 256))
+        assert len(data) == 3
+        assert data[0][0].shape == (2, 4, 16, 128, 256)