Repository: MouseLand/suite2p (language: python)

Issue:
FEATURE: Allow loading MESc files with image data
### Feature you'd like to see:

It would be nice to see "femtonics" option at run suite2p Input format combobox

### Attempted alternative approaches:

We have hdf5 based file format so our customers can use h5 option but they need to rename the filetype from .mesc to .h5 and modify h5 key from "data" to "/MSession_0/MUnit_0/Channel_0" for example.

### Additional Context

Let me know if you need more information. Alternatively, a user-defined type could be also cool.


Discussion / hints:

Fix patch:
diff --git a/.style.yapf b/.style.yapf
new file mode 100644
index 000000000..55240b9b8
--- /dev/null
+++ b/.style.yapf
@@ -0,0 +1,4 @@
+[style]
+based_on_style = google
+split_before_named_assigns = false
+column_limit = 88
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 3072537aa..000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,70 +0,0 @@
-language: python
-jobs:
-  include:
-  - name: Python 3.7.1 on Linux
-    dist: xenial
-    services:
-      - xvfb
-    python: 3.7
-    before_install:
-    - wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O
-      miniconda.sh
-    - bash ./miniconda.sh -b
-    - export PATH=~/miniconda3/bin:$PATH
-    - conda update --yes conda
-  - name: Python 3.7.1 on Linux Bionic
-    dist: bionic
-    services:
-      - xvfb
-    python: 3.7
-    before_install:
-      - wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O
-        miniconda.sh
-      - bash ./miniconda.sh -b
-      - export PATH=~/miniconda3/bin:$PATH
-      - conda update --yes conda
-  - name: Python 3.7.7 on macOS
-    os: osx
-    osx_image: xcode12
-    language: shell
-    before_install:
-    - wget https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh
-      -O miniconda.sh
-    - bash ./miniconda.sh -b
-    - export PATH=~/miniconda3/bin:$PATH
-    - conda update --yes conda
-  - name: Python 3.7.7 on Windows
-    os: windows
-    language: shell
-    before_install:
-    - choco install python --version 3.7.7
-    - export MINICONDA=/c/miniconda
-    - MINICONDA_WIN=$(cygpath --windows $MINICONDA)
-    - choco install openssl.light
-    - choco install miniconda3 --params="'/AddToPath:0 /D:$MINICONDA_WIN'"
-    - PATH=$(echo "$PATH" | sed -e 's|:/c/ProgramData/chocolatey/bin||')
-    - PATH=$(echo "$PATH" | sed -e 's|:/c/ProgramData/chocolatey/lib/mingw/tools/install/mingw64/bin||')
-    - source $MINICONDA/Scripts/activate
-    - source $MINICONDA/etc/profile.d/conda.sh
-  allow_failures:
-  - os: osx
-  - dist: bionic
-  - os: windows
-install:
-- conda env create -f environment.yml
-- source activate suite2p
-- pip install .[data,nwb]
-- dvc pull -r gdrive-travis
-- pip install coveralls
-script:
-- coverage run --source=suite2p --omit=suite2p/gui/* setup.py test
-after_success: coveralls
-deploy:
-  skip_cleanup: true
-  skip_existing: true
-  provider: pypi
-  user: __token__
-  password:
-    secure: iIUxK/XrLFS0yu7MwkXaAfuX0/CmaIVe+vFMOOdw+b1P1Yx+Lj+t074wrUS7/Ky0ZO9gY8PELnvqF+HQNbRUprMOl+P+4rdpJ5lw4LPWOMUSD14jiTaal3hYICOZSs/0sKFLYga0+/aCEYhOFfKOsPthlE6VDpUnmCvihGwZAFItnWJdq+/hKkLjOgLQbTCxLlQrudUYDRJWzgomoStjYt/B53YaoY2U2IC/RqfI5e2kOeNTK4qxWC6RnpjA81w0KMywkbWeSwB372j2+z180nvXEvsdln/QIq1bCpM3saKf2JjDDeKpq8r16sJ/pIr2OPldRMTa/UE6CvkssGWy7qA8lNbw/uwnMFIr/yvJboLJk/jG/4JjUWtJnNpDyzVt/o1DbimQDlQiacTwGmHlo4E/DrGQpbneSTU7Dfjg6ka5mvoxp2htMRRDfX1m9rdc/B7yjS49dN34GrWjcJiq24mlhYuACCLjZJvNF/CSUJg5JqR9aXpNjak0NOPs/JDs0mDWZNfdbcjff3+RXNEdpQVqYvayJsmEubnUoIPNm671Dc4xab5saEaxeS6oxwabCThQNhswksDEfzWtW8/7oAv2DfjfBEUClvjV6iD+NqWsRtotUrOXfSA/I6KjVsXVUBh+PhePwKceCT+M0Dp5WiRNbog6S7uEcCd2Nd0as38=
-  on:
-    tags: true
diff --git a/README.md b/README.md
index 37cb9ac10..109e45aa4 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,6 @@
 # suite2p <img src="suite2p/logo/logo_unshaded.png" width="250" title="sweet two pea" alt="sweet two pea" align="right" vspace = "50">
 
 [![Documentation Status](https://readthedocs.org/projects/suite2p/badge/?version=dev)](https://suite2p.readthedocs.io/en/dev/?badge=dev)
-[![Build Status](https://travis-ci.org/Mouseland/suite2p.svg?branch=dev)](https://travis-ci.org/Mouseland/suite2p)
 [![Coverage Status](https://coveralls.io/repos/github/MouseLand/suite2p/badge.svg?branch=dev)](https://coveralls.io/github/MouseLand/suite2p?branch=dev)
 [![PyPI version](https://badge.fury.io/py/suite2p.svg)](https://badge.fury.io/py/suite2p)
 [![Downloads](https://pepy.tech/badge/suite2p)](https://pepy.tech/project/suite2p)
@@ -38,6 +37,13 @@ The matlab version is available [here](https://github.com/cortex-lab/Suite2P). N
 
 Lectures on how suite2p works are available [here](https://youtu.be/HpL5XNtC5wU?list=PLutb8FMs2QdNqL4h4NrNhSHgLGk4sXarb).
 
+### CITATION
+
+If you use this package in your research, please cite the [paper](https://www.biorxiv.org/content/early/2017/07/20/061507):
+
+Pachitariu, M., Stringer, C., Schröder, S., Dipoppa, M., Rossi, L. F., Carandini, M., & Harris, K. D. (2016). Suite2p: beyond 10,000 neurons with standard two-photon microscopy. BioRxiv, 061507.
+
+
 ## Read the Documentation at https://suite2p.readthedocs.io/
 
 ## Installation
@@ -176,17 +182,14 @@ suite2p relies on the following excellent packages (which are automatically inst
 - [rastermap](https://github.com/MouseLand/rastermap)
 - [pyqtgraph](http://pyqtgraph.org/)
 - [PyQt5](http://pyqt.sourceforge.net/Docs/PyQt5/)
+- [torch](http://pytorch.org)
 - [numpy](http://www.numpy.org/) (>=1.16.0)
 - [numba](http://numba.pydata.org/numba-doc/latest/user/5minguide.html)
-- [mkl_fft](https://anaconda.org/conda-forge/mkl_fft)
 - [scanimage-tiff-reader](https://vidriotech.gitlab.io/scanimagetiffreader-python/)
 - [scipy](https://www.scipy.org/)
-- [h5py](https://www.h5py.org/)
 - [scikit-learn](http://scikit-learn.org/stable/)
-- [scanimage-tiff-reader](http://scanimage.gitlab.io/ScanImageTiffReaderDocs/)
 - [tifffile](https://pypi.org/project/tifffile/)
 - [natsort](https://natsort.readthedocs.io/en/master/)
-- [matplotlib](https://matplotlib.org/) (not for plotting (only using hsv_to_rgb and colormap function), should not conflict with PyQt5)
 
 ### Logo
 Logo was designed by Shelby Stringer and [Chris Czaja](http://chrisczaja.com/).
diff --git a/environment.yml b/environment.yml
deleted file mode 100644
index 8f41240bc..000000000
--- a/environment.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-name: suite2p
-channels:
-  - pytorch
-  - numba
-dependencies:
-  - python>=3.8,<3.9
-  - pip
-  - mkl
-  - tbb
-  - numpy
-  - numba
-  - matplotlib
-  - scikit-learn
-  - h5py=2.10.0
-  - pip:
-    - scipy>=1.4.0
-    - pyqt5
-    - pyqt5.sip
-    - pyqt5-tools
-    - torch>=1.7.1
-    - natsort
-    - rastermap>0.1.0
-    - tifffile
-    - scanimage-tiff-reader>=1.4.1
-    - pyqtgraph
-    - importlib-metadata
-    - paramiko
-    - pynwb
-    - sbxreader
-    - suite2p
diff --git a/setup.py b/setup.py
index 8e347ebe1..801da76b8 100644
--- a/setup.py
+++ b/setup.py
@@ -1,48 +1,52 @@
 import setuptools
 
-install_deps = ['importlib-metadata',
-        'natsort',
-        'rastermap>0.1.0',
-        'tifffile',
-        'scanimage-tiff-reader>=1.4.1',
-        'torch==1.13.1',
-        'paramiko',
-        'numpy>=1.24.3',
-        'numba>=0.57.0',
-        'matplotlib',
-        'scipy>=1.9.0',
-        'h5py',
-        'sbxreader',
-        'scikit-learn',
-        'cellpose',
-        'nd2']
+install_deps = ["importlib-metadata",
+        "natsort",
+        "rastermap>0.1.0",
+        "tifffile",
+        "torch>=1.13.1",
+        "numpy>=1.24.3",
+        "numba>=0.57.0",
+        "matplotlib",
+        "scipy>=1.9.0",
+        "scikit-learn",
+        "cellpose",
+        ]
 
 gui_deps = [
         "pyqt5",
         "pyqt5-tools",
         "pyqt5.sip",
-        'pyqtgraph',
-        'rastermap>0.1.0',
+        "pyqtgraph",
       ]
 
+io_deps = [
+    "scanimage-tiff-reader>=1.4.1",
+    "paramiko",
+    "nd2",
+    "sbxreader",
+    "h5py"
+]
+
 nwb_deps = [
         "pynwb>=2.3.2",
       ]
+
 test_deps = [
-      'pytest',
-      'tenacity',
-      'tqdm',
-      'pytest-qt==3.3.0',
+      "pytest",
+      "tenacity",
+      "tqdm",
+      "pytest-qt>3.3.0",
     ]
 
-all_deps = gui_deps + nwb_deps + test_deps
+all_deps = gui_deps + nwb_deps + test_deps + io_deps
 
 try:
     import torch
     a = torch.ones(2, 3)
-    version = int(torch.__version__[2])
-    if version >= 6:
-        install_deps.remove('torch>=1.7.1')
+    major_version, minor_version, _ = torch.__version__.split(".")
+    if major_version == "2" or int(minor_version) >= 6:
+        install_deps.remove("torch>=1.6")
 except:
     pass
 
@@ -59,22 +63,23 @@
     url="https://github.com/MouseLand/suite2p",
     packages=setuptools.find_packages(),
     setup_requires=[
-      'pytest-runner',
-      'setuptools_scm',
+      "pytest-runner",
+      "setuptools_scm",
     ],
     use_scm_version=True,
     install_requires=install_deps,
     tests_require=test_deps,
     extras_require={
       "docs": [
-        'sphinx>=3.0',
-        'sphinxcontrib-apidoc',
-        'sphinx_rtd_theme',
-        'sphinx-prompt',
-        'sphinx-autodoc-typehints',
+        "sphinx>=3.0",
+        "sphinxcontrib-apidoc",
+        "sphinx_rtd_theme",
+        "sphinx-prompt",
+        "sphinx-autodoc-typehints",
       ],
       "gui": gui_deps,
       "nwb": nwb_deps,
+      "io": io_deps,
       "tests": test_deps,
       "all": all_deps,
     },
@@ -85,10 +90,10 @@
         "Operating System :: OS Independent",
     ],
       entry_points = {
-        'console_scripts': [
-          'suite2p = suite2p.__main__:main',
-          'reg_metrics = benchmarks.registration_metrics:main',
-          'tiff2scanimage = scripts.make_tiff_scanimage_compatible:main',
+        "console_scripts": [
+          "suite2p = suite2p.__main__:main",
+          "reg_metrics = benchmarks.registration_metrics:main",
+          "tiff2scanimage = scripts.make_tiff_scanimage_compatible:main",
         ]
         },
 )
diff --git a/suite2p/__main__.py b/suite2p/__main__.py
index 5698af1d2..7d024127b 100644
--- a/suite2p/__main__.py
+++ b/suite2p/__main__.py
@@ -2,24 +2,26 @@
 import numpy as np
 from suite2p import default_ops, version
 
+
 def add_args(parser: argparse.ArgumentParser):
     """
     Adds suite2p ops arguments to parser.
     """
-    parser.add_argument('--single_plane', action='store_true', help='run single plane ops')
-    parser.add_argument('--ops', default=[], type=str, help='options')
-    parser.add_argument('--db', default=[], type=str, help='options')
-    parser.add_argument('--version', action='store_true', help='print version number.')
+    parser.add_argument("--single_plane", action="store_true",
+                        help="run single plane ops")
+    parser.add_argument("--ops", default=[], type=str, help="options")
+    parser.add_argument("--db", default=[], type=str, help="options")
+    parser.add_argument("--version", action="store_true", help="print version number.")
     ops0 = default_ops()
     for k in ops0.keys():
-        v = dict(default=ops0[k], help='{0} : {1}'.format(k, ops0[k]))
-        if k in ['fast_disk', 'save_folder', 'save_path0']:
-            v['default'] = None
-            v['type'] = str
-        if (type(v['default']) in [np.ndarray, list]) and len(v['default']):
-            v['nargs'] = '+'
-            v['type'] = type(v['default'][0])
-        parser.add_argument('--'+k, **v)
+        v = dict(default=ops0[k], help="{0} : {1}".format(k, ops0[k]))
+        if k in ["fast_disk", "save_folder", "save_path0"]:
+            v["default"] = None
+            v["type"] = str
+        if (type(v["default"]) in [np.ndarray, list]) and len(v["default"]):
+            v["nargs"] = "+"
+            v["type"] = type(v["default"][0])
+        parser.add_argument("--" + k, **v)
     return parser
 
 
@@ -31,12 +33,12 @@ def parse_args(parser: argparse.ArgumentParser):
     dargs = vars(args)
     ops0 = default_ops()
     ops = np.load(args.ops, allow_pickle=True).item() if args.ops else {}
-    set_param_msg = '->> Setting {0} to {1}'
+    set_param_msg = "->> Setting {0} to {1}"
     # options defined in the cli take precedence over the ones in the ops file
     for k in ops0:
         default_key = ops0[k]
         args_key = dargs[k]
-        if k in ['fast_disk', 'save_folder', 'save_path0']:
+        if k in ["fast_disk", "save_folder", "save_path0"]:
             if args_key:
                 ops[k] = args_key
                 print(set_param_msg.format(k, ops[k]))
@@ -46,7 +48,7 @@ def parse_args(parser: argparse.ArgumentParser):
                 ops[k] = n.astype(type(default_key))
                 print(set_param_msg.format(k, ops[k]))
         elif isinstance(default_key, bool):
-            args_key = bool(int(args_key))  # bool('0') is true, must convert to int
+            args_key = bool(int(args_key))  # bool("0") is true, must convert to int
             if default_key != args_key:
                 ops[k] = args_key
                 print(set_param_msg.format(k, ops[k]))
@@ -58,7 +60,8 @@ def parse_args(parser: argparse.ArgumentParser):
 
 
 def main():
-    args, ops = parse_args(add_args(argparse.ArgumentParser(description='Suite2p parameters')))
+    args, ops = parse_args(
+        add_args(argparse.ArgumentParser(description="Suite2p parameters")))
     if args.version:
         print("suite2p v{}".format(version))
     elif args.single_plane and args.ops:
@@ -74,5 +77,5 @@ def main():
         gui.run()
 
 
-if __name__ == '__main__':
-    main()
\ No newline at end of file
+if __name__ == "__main__":
+    main()
diff --git a/suite2p/classification/classifier.py b/suite2p/classification/classifier.py
index 5d73aaa68..6032b8773 100644
--- a/suite2p/classification/classifier.py
+++ b/suite2p/classification/classifier.py
@@ -1,6 +1,6 @@
 import numpy as np
 from scipy.ndimage import gaussian_filter
-from sklearn.linear_model  import LogisticRegression
+from sklearn.linear_model import LogisticRegression
 
 
 class Classifier:
@@ -16,6 +16,7 @@ class Classifier:
         keys of ROI stat to use to classify
 
     """
+
     def __init__(self, classfile=None, keys=None):
         # stat are cell stats from currently loaded recording
         # classfile is a previously saved classifier file
@@ -42,23 +43,23 @@ def load(self, classfile, keys=None):
         try:
             model = np.load(classfile, allow_pickle=True).item()
             if keys is None:
-                self.keys = model['keys']
-                self.stats = model['stats']
+                self.keys = model["keys"]
+                self.stats = model["stats"]
             else:
-                model['keys'] = np.array(model['keys'])
-                ikey = np.isin(model['keys'], keys)
-                self.keys = model['keys'][ikey].tolist()
-                self.stats = model['stats'][:,ikey]
-            self.iscell = model['iscell']
+                model["keys"] = np.array(model["keys"])
+                ikey = np.isin(model["keys"], keys)
+                self.keys = model["keys"][ikey].tolist()
+                self.stats = model["stats"][:, ikey]
+            self.iscell = model["iscell"]
             self.loaded = True
             self.classfile = classfile
             self._fit()
         except (ValueError, KeyError, OSError, RuntimeError, TypeError, NameError):
-            print('ERROR: incorrect classifier file')
+            print("ERROR: incorrect classifier file")
             self.loaded = False
 
     def run(self, stat, p_threshold: float = 0.5) -> np.ndarray:
-        """Returns cell classification thresholded with 'p_threshold' and its probability."""
+        """Returns cell classification thresholded with "p_threshold" and its probability."""
         probcell = self.predict_proba(stat)
         is_cell = probcell > p_threshold
         return np.stack([is_cell, probcell]).T
@@ -75,14 +76,19 @@ def predict_proba(self, stat):
             needs self.keys keys
 
         """
-        test_stats = np.array([stat[j][k] for j in range(len(stat)) for k in self.keys]).reshape(len(stat), -1)
+        test_stats = np.array([stat[j][k] for j in range(len(stat)) for k in self.keys
+                              ]).reshape(len(stat), -1)
         logp = self._get_logp(test_stats)
         y_pred = self.model.predict_proba(logp)[:, 1]
         return y_pred
 
     def save(self, filename: str) -> None:
         """ save classifier to filename """
-        np.save(filename, {'stats': self.stats, 'iscell': self.iscell, 'keys': self.keys})
+        np.save(filename, {
+            "stats": self.stats,
+            "iscell": self.iscell,
+            "keys": self.keys
+        })
 
     def _get_logp(self, stats):
         """ compute log probability of set of stats
@@ -96,33 +102,30 @@ def _get_logp(self, stats):
         """
         logp = np.zeros(stats.shape)
         for n in range(stats.shape[1]):
-            x = stats[:,n]
-            x[x<self.grid[0,n]]   = self.grid[0,n]
-            x[x>self.grid[-1,n]]  = self.grid[-1,n]
-            x[np.isnan(x)] = self.grid[0,n]
-            ibin = np.digitize(x, self.grid[:,n], right=True) - 1
-            logp[:,n] = np.log(self.p[ibin,n] + 1e-6) - np.log(1-self.p[ibin,n] + 1e-6)
+            x = stats[:, n]
+            x[x < self.grid[0, n]] = self.grid[0, n]
+            x[x > self.grid[-1, n]] = self.grid[-1, n]
+            x[np.isnan(x)] = self.grid[0, n]
+            ibin = np.digitize(x, self.grid[:, n], right=True) - 1
+            logp[:, n] = np.log(self.p[ibin, n] + 1e-6) - np.log(1 - self.p[ibin, n] +
+                                                                 1e-6)
         return logp
 
     def _fit(self):
         """ fit logistic regression model using stats, keys and iscell """
         nodes = 100
         ncells, nstats = self.stats.shape
-        ssort= np.sort(self.stats, axis=0)
-        isort= np.argsort(self.stats, axis=0)
-        ix = np.linspace(0, ncells-1, nodes).astype('int32')
+        ssort = np.sort(self.stats, axis=0)
+        isort = np.argsort(self.stats, axis=0)
+        ix = np.linspace(0, ncells - 1, nodes).astype("int32")
         grid = ssort[ix, :]
-        p = np.zeros((nodes-1,nstats))
-        for j in range(nodes-1):
+        p = np.zeros((nodes - 1, nstats))
+        for j in range(nodes - 1):
             for k in range(nstats):
-                p[j, k] = np.mean(self.iscell[isort[ix[j]:ix[j+1], k]])
+                p[j, k] = np.mean(self.iscell[isort[ix[j]:ix[j + 1], k]])
         p = gaussian_filter(p, (2., 0))
-        self.grid = grid 
+        self.grid = grid
         self.p = p
         logp = self._get_logp(self.stats)
-        self.model = LogisticRegression(C = 100., solver='liblinear')
+        self.model = LogisticRegression(C=100., solver="liblinear")
         self.model.fit(logp, self.iscell)
-
-    
-
-
diff --git a/suite2p/classification/classify.py b/suite2p/classification/classify.py
index 18a535991..ad8152c5d 100644
--- a/suite2p/classification/classify.py
+++ b/suite2p/classification/classify.py
@@ -3,14 +3,16 @@
 from typing import Union, Sequence
 from .classifier import Classifier
 
-builtin_classfile = Path(__file__).joinpath('../../classifiers/classifier.npy').resolve()
-user_classfile = Path.home().joinpath('.suite2p/classifiers/classifier_user.npy')
+builtin_classfile = Path(__file__).joinpath(
+    "../../classifiers/classifier.npy").resolve()
+user_classfile = Path.home().joinpath(".suite2p/classifiers/classifier_user.npy")
 
 
-def classify(stat: np.ndarray,
-             classfile: Union[str, Path],
-             keys: Sequence[str] = ('npix_norm', 'compact', 'skew'),
-             ):
+def classify(
+        stat: np.ndarray,
+        classfile: Union[str, Path],
+        keys: Sequence[str] = ("npix_norm", "compact", "skew"),
+):
     """ 
     Main classification function 
     
@@ -19,7 +21,7 @@ def classify(stat: np.ndarray,
     Parameters
     ----------------
 
-    stat: dictionary 'ypix', 'xpix', 'lam'
+    stat: dictionary "ypix", "xpix", "lam"
         Dictionary containing statistics for ROIs
 
     classfile: string (optional, default None)
diff --git a/suite2p/default_ops.py b/suite2p/default_ops.py
index 0893b1dd2..00878d59a 100644
--- a/suite2p/default_ops.py
+++ b/suite2p/default_ops.py
@@ -1,122 +1,162 @@
 from .version import version
 
+
 def default_ops():
     """ default options to run pipeline """
     return {
         # Suite2p version
-        'suite2p_version': version, #current version of suite2p used for pipeline
+        "suite2p_version": version,  #current version of suite2p used for pipeline
 
         # file input/output settings
-        'look_one_level_down': False,  # whether to look in all subfolders when searching for tiffs
-        'fast_disk': [],  # used to store temporary binary file, defaults to save_path0
-        'delete_bin': False,  # whether to delete binary file after processing
-        'mesoscan': False,  # for reading in scanimage mesoscope files
-        'bruker': False,  # whether or not single page BRUKER tiffs!
-        'bruker_bidirectional': False, # bidirectional multiplane in bruker: 0, 1, 2, 2, 1, 0 (True) vs 0, 1, 2, 0, 1, 2 (False)
-        'h5py': [],  # take h5py as input (deactivates data_path)
-        'h5py_key': 'data',  #key in h5py where data array is stored
-        'nwb_file': '', # take nwb file as input (deactivates data_path)
-        'nwb_driver': '', # driver for nwb file (nothing if file is local)
-        'nwb_series': '', # TwoPhotonSeries name, defaults to first TwoPhotonSeries in nwb file
-        'save_path0': [],  # stores results, defaults to first item in data_path
-        'save_folder': [], # directory you'd like suite2p results to be saved to
-        'subfolders': [], # subfolders you'd like to search through when look_one_level_down is set to True
-        'move_bin': False,  # if 1, and fast_disk is different than save_disk, binary file is moved to save_disk
+        "look_one_level_down":
+            False,  # whether to look in all subfolders when searching for tiffs
+        "fast_disk": [],  # used to store temporary binary file, defaults to save_path0
+        "delete_bin": False,  # whether to delete binary file after processing
+        "mesoscan": False,  # for reading in scanimage mesoscope files
+        "bruker": False,  # whether or not single page BRUKER tiffs!
+        "bruker_bidirectional":
+            False,  # bidirectional multiplane in bruker: 0, 1, 2, 2, 1, 0 (True) vs 0, 1, 2, 0, 1, 2 (False)
+        "h5py": [],  # take h5py as input (deactivates data_path)
+        "h5py_key": "data",  #key in h5py where data array is stored
+        "nwb_file": "",  # take nwb file as input (deactivates data_path)
+        "nwb_driver": "",  # driver for nwb file (nothing if file is local)
+        "nwb_series":
+            "",  # TwoPhotonSeries name, defaults to first TwoPhotonSeries in nwb file
+        "save_path0": [],  # stores results, defaults to first item in data_path
+        "save_folder": [],  # directory you"d like suite2p results to be saved to
+        "subfolders": [
+        ],  # subfolders you"d like to search through when look_one_level_down is set to True
+        "move_bin":
+            False,  # if 1, and fast_disk is different than save_disk, binary file is moved to save_disk
 
         # main settings
-        'nplanes' : 1,  # each tiff has these many planes in sequence
-        'nchannels' : 1,  # each tiff has these many channels per plane
-        'functional_chan' : 1,  # this channel is used to extract functional ROIs (1-based)
-        'tau':  1.,  # this is the main parameter for deconvolution
-        'fs': 10.,  # sampling rate (PER PLANE e.g. for 12 plane recordings it will be around 2.5)
-        'force_sktiff': False, # whether or not to use scikit-image for tiff reading
-        'frames_include': -1,
-        'multiplane_parallel': False, # whether or not to run on server
-        'ignore_flyback': [],
+        "nplanes": 1,  # each tiff has these many planes in sequence
+        "nchannels": 1,  # each tiff has these many channels per plane
+        "functional_chan":
+            1,  # this channel is used to extract functional ROIs (1-based)
+        "tau": 1.,  # this is the main parameter for deconvolution
+        "fs":
+            10.,  # sampling rate (PER PLANE e.g. for 12 plane recordings it will be around 2.5)
+        "force_sktiff": False,  # whether or not to use scikit-image for tiff reading
+        "frames_include": -1,
+        "multiplane_parallel": False,  # whether or not to run on server
+        "ignore_flyback": [],
 
         # output settings
-        'preclassify': 0.0,  # apply classifier before signal extraction with probability 0.3
-        'save_mat': False,  # whether to save output as matlab files
-        'save_NWB': False,  # whether to save output as NWB file
-        'combined': True,  # combine multiple planes into a single result /single canvas for GUI
-        'aspect': 1.0,  # um/pixels in X / um/pixels in Y (for correct aspect ratio in GUI)
+        "preclassify":
+            0.0,  # apply classifier before signal extraction with probability 0.3
+        "save_mat": False,  # whether to save output as matlab files
+        "save_NWB": False,  # whether to save output as NWB file
+        "combined":
+            True,  # combine multiple planes into a single result /single canvas for GUI
+        "aspect":
+            1.0,  # um/pixels in X / um/pixels in Y (for correct aspect ratio in GUI)
 
         # bidirectional phase offset
-        'do_bidiphase': False, #whether or not to compute bidirectional phase offset (applies to 2P recordings only)
-        'bidiphase': 0, # Bidirectional Phase offset from line scanning (set by user). Applied to all frames in recording.
-        'bidi_corrected': False, # Whether to do bidirectional correction during registration
+        "do_bidiphase":
+            False,  #whether or not to compute bidirectional phase offset (applies to 2P recordings only)
+        "bidiphase":
+            0,  # Bidirectional Phase offset from line scanning (set by user). Applied to all frames in recording.
+        "bidi_corrected":
+            False,  # Whether to do bidirectional correction during registration
 
         # registration settings
-        'do_registration': True,  # whether to register data (2 forces re-registration)
-        'two_step_registration': False, # whether or not to run registration twice (useful for low SNR data). Set keep_movie_raw to True if setting this parameter to True. 
-        'keep_movie_raw': False, # whether to keep binary file of non-registered frames. 
-        'nimg_init': 300,  # subsampled frames for finding reference image
-        'batch_size': 500,  # number of frames per batch
-        'maxregshift': 0.1,  # max allowed registration shift, as a fraction of frame max(width and height)
-        'align_by_chan' : 1,  # when multi-channel, you can align by non-functional channel (1-based)
-        'reg_tif': False,  # whether to save registered tiffs
-        'reg_tif_chan2': False,  # whether to save channel 2 registered tiffs
-        'subpixel' : 10,  # precision of subpixel registration (1/subpixel steps)
-        'smooth_sigma_time': 0,  # gaussian smoothing in time
-        'smooth_sigma': 1.15,  # ~1 good for 2P recordings, recommend 3-5 for 1P recordings
-        'th_badframes': 1.0,  # this parameter determines which frames to exclude when determining cropping - set it smaller to exclude more frames
-        'norm_frames': True, # normalize frames when detecting shifts
-        'force_refImg': False, # if True, use refImg stored in ops if available
-        'pad_fft': False, # if True, pads image during FFT part of registration
-        
+        "do_registration": True,  # whether to register data (2 forces re-registration)
+        "two_step_registration":
+            False,  # whether or not to run registration twice (useful for low SNR data). Set keep_movie_raw to True if setting this parameter to True. 
+        "keep_movie_raw":
+            False,  # whether to keep binary file of non-registered frames. 
+        "nimg_init": 300,  # subsampled frames for finding reference image
+        "batch_size": 500,  # number of frames per batch
+        "maxregshift":
+            0.1,  # max allowed registration shift, as a fraction of frame max(width and height)
+        "align_by_chan":
+            1,  # when multi-channel, you can align by non-functional channel (1-based)
+        "reg_tif": False,  # whether to save registered tiffs
+        "reg_tif_chan2": False,  # whether to save channel 2 registered tiffs
+        "subpixel": 10,  # precision of subpixel registration (1/subpixel steps)
+        "smooth_sigma_time": 0,  # gaussian smoothing in time
+        "smooth_sigma":
+            1.15,  # ~1 good for 2P recordings, recommend 3-5 for 1P recordings
+        "th_badframes":
+            1.0,  # this parameter determines which frames to exclude when determining cropping - set it smaller to exclude more frames
+        "norm_frames": True,  # normalize frames when detecting shifts
+        "force_refImg": False,  # if True, use refImg stored in ops if available
+        "pad_fft": False,  # if True, pads image during FFT part of registration
+
         # non rigid registration settings
-        'nonrigid': True,  # whether to use nonrigid registration
-        'block_size': [128, 128],  # block size to register (** keep this a multiple of 2 **)
-        'snr_thresh': 1.2,  # if any nonrigid block is below this threshold, it gets smoothed until above this threshold. 1.0 results in no smoothing
-        'maxregshiftNR': 5,  # maximum pixel shift allowed for nonrigid, relative to rigid
+        "nonrigid": True,  # whether to use nonrigid registration
+        "block_size": [128,
+                       128],  # block size to register (** keep this a multiple of 2 **)
+        "snr_thresh":
+            1.2,  # if any nonrigid block is below this threshold, it gets smoothed until above this threshold. 1.0 results in no smoothing
+        "maxregshiftNR":
+            5,  # maximum pixel shift allowed for nonrigid, relative to rigid
 
         # 1P settings
-        '1Preg': False,  # whether to perform high-pass filtering and tapering
-        'spatial_hp_reg': 42,  # window for spatial high-pass filtering before registration
-        'pre_smooth': 0,  # whether to smooth before high-pass filtering before registration
-        'spatial_taper': 40,  # how much to ignore on edges (important for vignetted windows, for FFT padding do not set BELOW 3*ops['smooth_sigma'])
+        "1Preg": False,  # whether to perform high-pass filtering and tapering
+        "spatial_hp_reg":
+            42,  # window for spatial high-pass filtering before registration
+        "pre_smooth":
+            0,  # whether to smooth before high-pass filtering before registration
+        "spatial_taper":
+            40,  # how much to ignore on edges (important for vignetted windows, for FFT padding do not set BELOW 3*ops["smooth_sigma"])
 
         # cell detection settings with suite2p
-        'roidetect': True,  # whether or not to run ROI extraction
-        'spikedetect': True,  # whether or not to run spike deconvolution
-        'sparse_mode': True,  # whether or not to run sparse_mode
-        'spatial_scale': 0,  # 0: multi-scale; 1: 6 pixels, 2: 12 pixels, 3: 24 pixels, 4: 48 pixels
-        'connected': True,  # whether or not to keep ROIs fully connected (set to 0 for dendrites)
-        'nbinned': 5000,  # max number of binned frames for cell detection
-        'max_iterations': 20,  # maximum number of iterations to do cell detection
-        'threshold_scaling': 1.0,  # adjust the automatically determined threshold by this scalar multiplier
-        'max_overlap': 0.75,  # cells with more overlap than this get removed during triage, before refinement
-        'high_pass': 100,  # running mean subtraction with window of size 'high_pass' (use low values for 1P)
-        'spatial_hp_detect': 25,  # window for spatial high-pass filtering for neuropil subtraction before detection
-        'denoise': False, # denoise binned movie for cell detection in sparse_mode
+        "roidetect": True,  # whether or not to run ROI extraction
+        "spikedetect": True,  # whether or not to run spike deconvolution
+        "sparse_mode": True,  # whether or not to run sparse_mode
+        "spatial_scale":
+            0,  # 0: multi-scale; 1: 6 pixels, 2: 12 pixels, 3: 24 pixels, 4: 48 pixels
+        "connected":
+            True,  # whether or not to keep ROIs fully connected (set to 0 for dendrites)
+        "nbinned": 5000,  # max number of binned frames for cell detection
+        "max_iterations": 20,  # maximum number of iterations to do cell detection
+        "threshold_scaling":
+            1.0,  # adjust the automatically determined threshold by this scalar multiplier
+        "max_overlap":
+            0.75,  # cells with more overlap than this get removed during triage, before refinement
+        "high_pass":
+            100,  # running mean subtraction with window of size "high_pass" (use low values for 1P)
+        "spatial_hp_detect":
+            25,  # window for spatial high-pass filtering for neuropil subtraction before detection
+        "denoise": False,  # denoise binned movie for cell detection in sparse_mode
 
         # cell detection settings with cellpose (used if anatomical_only > 0)
-        'anatomical_only': 0, # run cellpose to get masks on 1: max_proj / mean_img; 2: mean_img; 3: mean_img enhanced, 4: max_proj
-        'diameter': 0,  # use diameter for cellpose, if 0 estimate diameter
-        'cellprob_threshold': 0.0, # cellprob_threshold for cellpose
-        'flow_threshold': 1.5, # flow_threshold for cellpose
-        'spatial_hp_cp': 0, # high-pass image spatially by a multiple of the diameter
-        'pretrained_model': 'cyto', # path to pretrained model or model type string in Cellpose (can be user model)
+        "anatomical_only":
+            0,  # run cellpose to get masks on 1: max_proj / mean_img; 2: mean_img; 3: mean_img enhanced, 4: max_proj
+        "diameter": 0,  # use diameter for cellpose, if 0 estimate diameter
+        "cellprob_threshold": 0.0,  # cellprob_threshold for cellpose
+        "flow_threshold": 1.5,  # flow_threshold for cellpose
+        "spatial_hp_cp": 0,  # high-pass image spatially by a multiple of the diameter
+        "pretrained_model":
+            "cyto",  # path to pretrained model or model type string in Cellpose (can be user model)
 
         # classification parameters
-        'soma_crop': True, # crop dendrites for cell classification stats like compactness
+        "soma_crop":
+            True,  # crop dendrites for cell classification stats like compactness
         # ROI extraction parameters
-        'neuropil_extract': True, # whether or not to extract neuropil; if False, Fneu is set to zero
-        'inner_neuropil_radius': 2,  # number of pixels to keep between ROI and neuropil donut
-        'min_neuropil_pixels': 350,  # minimum number of pixels in the neuropil
-        'lam_percentile': 50., # percentile of lambda within area to ignore when excluding cell pixels for neuropil extraction
-        'allow_overlap': False,  # pixels that are overlapping are thrown out (False) or added to both ROIs (True)
-        'use_builtin_classifier': False,  # whether or not to use built-in classifier for cell detection (overrides
-                                         # classifier specified in classifier_path if set to True)
-        'classifier_path': '', # path to classifier
-        
-        # channel 2 detection settings (stat[n]['chan2'], stat[n]['not_chan2'])
-        'chan2_thres': 0.65,  # minimum for detection of brightness on channel 2
+        "neuropil_extract":
+            True,  # whether or not to extract neuropil; if False, Fneu is set to zero
+        "inner_neuropil_radius":
+            2,  # number of pixels to keep between ROI and neuropil donut
+        "min_neuropil_pixels": 350,  # minimum number of pixels in the neuropil
+        "lam_percentile":
+            50.,  # percentile of lambda within area to ignore when excluding cell pixels for neuropil extraction
+        "allow_overlap":
+            False,  # pixels that are overlapping are thrown out (False) or added to both ROIs (True)
+        "use_builtin_classifier":
+            False,  # whether or not to use built-in classifier for cell detection (overrides
+        # classifier specified in classifier_path if set to True)
+        "classifier_path": "",  # path to classifier
+
+        # channel 2 detection settings (stat[n]["chan2"], stat[n]["not_chan2"])
+        "chan2_thres": 0.65,  # minimum for detection of brightness on channel 2
 
         # deconvolution settings
-        'baseline': 'maximin',  # baselining mode (can also choose 'prctile')
-        'win_baseline': 60.,  # window for maximin
-        'sig_baseline': 10.,  # smoothing constant for gaussian filter
-        'prctile_baseline': 8.,  # optional (whether to use a percentile baseline)
-        'neucoeff': 0.7,  # neuropil coefficient
-    }
\ No newline at end of file
+        "baseline": "maximin",  # baselining mode (can also choose "prctile")
+        "win_baseline": 60.,  # window for maximin
+        "sig_baseline": 10.,  # smoothing constant for gaussian filter
+        "prctile_baseline": 8.,  # optional (whether to use a percentile baseline)
+        "neucoeff": 0.7,  # neuropil coefficient
+    }
diff --git a/suite2p/detection/anatomical.py b/suite2p/detection/anatomical.py
index 0d85bda95..6dc7feec0 100644
--- a/suite2p/detection/anatomical.py
+++ b/suite2p/detection/anatomical.py
@@ -12,132 +12,140 @@
 from . import utils
 from .stats import roi_stats
 
+
 def mask_centers(masks):
     centers = np.zeros((masks.max(), 2), np.int32)
     diams = np.zeros(masks.max(), np.float32)
     slices = find_objects(masks)
-    for i,si in enumerate(slices):
+    for i, si in enumerate(slices):
         if si is not None:
-            sr,sc = si
-            ymed, xmed, diam = utils.mask_stats(masks[sr, sc] == (i+1))
+            sr, sc = si
+            ymed, xmed, diam = utils.mask_stats(masks[sr, sc] == (i + 1))
             centers[i] = np.array([ymed, xmed])
             diams[i] = diam
     return centers, diams
 
+
 def patch_detect(patches, diam):
     """ anatomical detection of masks from top active frames for putative cell """
-    print('refining masks using cellpose')
+    print("refining masks using cellpose")
     npatches = len(patches)
     ly = patches[0].shape[0]
     model = Cellpose(net_avg=False)
     imgs = np.zeros((npatches, ly, ly, 2), np.float32)
-    for i,m in enumerate(patches):
-        imgs[i,:,:,0] = transforms.normalize99(m)
+    for i, m in enumerate(patches):
+        imgs[i, :, :, 0] = transforms.normalize99(m)
     rsz = 30. / diam
-    imgs = transforms.resize_image(imgs, rsz=rsz).transpose(0,3,1,2)
+    imgs = transforms.resize_image(imgs, rsz=rsz).transpose(0, 3, 1, 2)
     imgs, ysub, xsub = transforms.pad_image_ND(imgs)
-        
+
     pmasks = np.zeros((npatches, ly, ly), np.uint16)
     batch_size = 8 * 224 // ly
-    tic=time.time()
+    tic = time.time()
     for j in np.arange(0, npatches, batch_size):
-        y = model.cp.network(imgs[j:j+batch_size])[0]
-        y = y[:, :, ysub[0]:ysub[-1]+1, xsub[0]:xsub[-1]+1]
+        y = model.cp.network(imgs[j:j + batch_size])[0]
+        y = y[:, :, ysub[0]:ysub[-1] + 1, xsub[0]:xsub[-1] + 1]
         y = y.asnumpy()
-        for i,yi in enumerate(y):
+        for i, yi in enumerate(y):
             cellprob = yi[-1]
             dP = yi[:2]
             niter = 1 / rsz * 200
-            p = dynamics.follow_flows(-1 * dP * (cellprob>0) / 5., 
-                                        niter=niter)
-            maski = dynamics.get_masks(p, iscell=(cellprob>0),
-                                        flows=dP, threshold=1.0)
+            p = dynamics.follow_flows(-1 * dP * (cellprob > 0) / 5., niter=niter)
+            maski = dynamics.get_masks(p, iscell=(cellprob > 0), flows=dP,
+                                       threshold=1.0)
             maski = fill_holes_and_remove_small_masks(maski)
-            maski = transforms.resize_image(maski, ly, ly, 
+            maski = transforms.resize_image(maski, ly, ly,
                                             interpolation=cv2.INTER_NEAREST)
-            pmasks[j+i] = maski
-        if j%5==0:
-            print('%d / %d masks created in %0.2fs'%(j+batch_size, npatches, time.time()-tic))
+            pmasks[j + i] = maski
+        if j % 5 == 0:
+            print("%d / %d masks created in %0.2fs" %
+                  (j + batch_size, npatches, time.time() - tic))
     return pmasks
 
+
 def refine_masks(stats, patches, seeds, diam, Lyc, Lxc):
     nmasks = len(patches)
     patch_masks = patch_detect(patches, diam)
     ly = patches[0].shape[0] // 2
-    igood = np.zeros(nmasks, 'bool')
-    for i, (patch_mask, stat, (yi,xi)) in enumerate(zip(patch_masks, stats, seeds)):
+    igood = np.zeros(nmasks, "bool")
+    for i, (patch_mask, stat, (yi, xi)) in enumerate(zip(patch_masks, stats, seeds)):
         mask = np.zeros((Lyc, Lxc), np.float32)
-        ypix0, xpix0= stat['ypix'], stat['xpix']
-        mask[ypix0, xpix0] = stat['lam']
+        ypix0, xpix0 = stat["ypix"], stat["xpix"]
+        mask[ypix0, xpix0] = stat["lam"]
         func_mask = utils.square_mask(mask, ly, yi, xi)
-        ious = utils.mask_ious(patch_mask.astype(np.uint16), 
-                               (func_mask>0).astype(np.uint16))[0]
-        if len(ious)>0 and ious.max() > 0.45:
+        ious = utils.mask_ious(patch_mask.astype(np.uint16), (func_mask
+                                                              > 0).astype(np.uint16))[0]
+        if len(ious) > 0 and ious.max() > 0.45:
             mask_id = np.argmax(ious) + 1
-            patch_mask = patch_mask[max(0, ly-yi) : min(2*ly, Lyc+ly-yi), 
-                                    max(0, ly-xi) : min(2*ly, Lxc+ly-xi)]
-            func_mask  =  func_mask[max(0, ly-yi) : min(2*ly, Lyc+ly-yi), 
-                                    max(0, ly-xi) : min(2*ly, Lxc+ly-xi)]
-            ypix0, xpix0 = np.nonzero(patch_mask==mask_id)
+            patch_mask = patch_mask[max(0, ly - yi):min(2 * ly, Lyc + ly - yi),
+                                    max(0, ly - xi):min(2 * ly, Lxc + ly - xi)]
+            func_mask = func_mask[max(0, ly - yi):min(2 * ly, Lyc + ly - yi),
+                                  max(0, ly - xi):min(2 * ly, Lxc + ly - xi)]
+            ypix0, xpix0 = np.nonzero(patch_mask == mask_id)
             lam0 = func_mask[ypix0, xpix0]
-            lam0[lam0<=0] = lam0.min()
-            ypix0 = ypix0 + max(0, yi-ly)
-            xpix0 = xpix0 + max(0, xi-ly)
+            lam0[lam0 <= 0] = lam0.min()
+            ypix0 = ypix0 + max(0, yi - ly)
+            xpix0 = xpix0 + max(0, xi - ly)
             igood[i] = True
-            stat['ypix'] = ypix0 
-            stat['xpix'] = xpix0 
-            stat['lam'] = lam0
-            stat['anatomical'] = True
+            stat["ypix"] = ypix0
+            stat["xpix"] = xpix0
+            stat["lam"] = lam0
+            stat["anatomical"] = True
         else:
-            stat['anatomical'] = False
-    return stats   
+            stat["anatomical"] = False
+    return stats
+
 
-def roi_detect(mproj, diameter=None, cellprob_threshold=0.0, flow_threshold=1.5, pretrained_model=None):
+def roi_detect(mproj, diameter=None, cellprob_threshold=0.0, flow_threshold=1.5,
+               pretrained_model=None):
     if not os.path.exists(pretrained_model):
         model = CellposeModel(model_type=pretrained_model)
     else:
         model = CellposeModel(pretrained_model=pretrained_model)
-    masks = model.eval(mproj, net_avg=True, channels=[0,0], diameter=diameter, 
-                        cellprob_threshold=cellprob_threshold, flow_threshold=flow_threshold)[0]
+    masks = model.eval(mproj, net_avg=True, channels=[0, 0], diameter=diameter,
+                       cellprob_threshold=cellprob_threshold,
+                       flow_threshold=flow_threshold)[0]
     shape = masks.shape
     _, masks = np.unique(np.int32(masks), return_inverse=True)
     masks = masks.reshape(shape)
     centers, mask_diams = mask_centers(masks)
     median_diam = np.median(mask_diams)
-    print('>>>> %d masks detected, median diameter = %0.2f ' % (masks.max(), median_diam))
+    print(">>>> %d masks detected, median diameter = %0.2f " %
+          (masks.max(), median_diam))
     return masks, centers, median_diam, mask_diams.astype(np.int32)
 
+
 def masks_to_stats(masks, weights):
     stats = []
     slices = find_objects(masks)
-    for i,si in enumerate(slices):
-        sr,sc = si
-        ypix0, xpix0 = np.nonzero(masks[sr, sc]==(i+1))
+    for i, si in enumerate(slices):
+        sr, sc = si
+        ypix0, xpix0 = np.nonzero(masks[sr, sc] == (i + 1))
         ypix0 = ypix0.astype(int) + sr.start
         xpix0 = xpix0.astype(int) + sc.start
         ymed = np.median(ypix0)
         xmed = np.median(xpix0)
-        imin = np.argmin((xpix0-xmed)**2 + (ypix0-ymed)**2)
+        imin = np.argmin((xpix0 - xmed)**2 + (ypix0 - ymed)**2)
         xmed = xpix0[imin]
         ymed = ypix0[imin]
         stats.append({
-            'ypix': ypix0,
-            'xpix': xpix0,
-            'lam': weights[ypix0, xpix0],
-            'med': [ymed, xmed],
-            'footprint': 1
+            "ypix": ypix0,
+            "xpix": xpix0,
+            "lam": weights[ypix0, xpix0],
+            "med": [ymed, xmed],
+            "footprint": 1
         })
     stats = np.array(stats)
     return stats
-    
-def select_rois(ops: Dict[str, Any], mov: np.ndarray,
-                diameter=None):
+
+
+def select_rois(ops: Dict[str, Any], mov: np.ndarray, diameter=None):
     """ find ROIs in static frames
     
     Parameters:
 
         ops: dictionary
-            requires keys 'high_pass', 'anatomical_only', optional 'yrange', 'xrange'
+            requires keys "high_pass", "anatomical_only", optional "yrange", "xrange"
         
         mov: ndarray t x Lyc x Lxc, binned movie
     
@@ -145,84 +153,92 @@ def select_rois(ops: Dict[str, Any], mov: np.ndarray,
         stats: list of dicts
     
     """
-    Lyc,Lxc = mov.shape[1:]
+    Lyc, Lxc = mov.shape[1:]
     mean_img = mov.mean(axis=0)
-    mov = utils.temporal_high_pass_filter(mov=mov, width=int(ops['high_pass']))
+    mov = utils.temporal_high_pass_filter(mov=mov, width=int(ops["high_pass"]))
     max_proj = mov.max(axis=0)
     #max_proj = np.percentile(mov, 90, axis=0) #.mean(axis=0)
-    if ops['anatomical_only'] == 1:
+    if ops["anatomical_only"] == 1:
         img = np.log(np.maximum(1e-3, max_proj / np.maximum(1e-3, mean_img)))
         weights = max_proj
-    elif ops['anatomical_only']==2:
+    elif ops["anatomical_only"] == 2:
         img = mean_img
-        weights = 0.1 + np.clip((mean_img - np.percentile(mean_img,1)) / 
-                                (np.percentile(mean_img,99) - np.percentile(mean_img,1)), 0, 1)
-    elif ops['anatomical_only']==3:
-        if 'meanImgE' in ops:
-            img = ops['meanImgE'][ops['yrange'][0]:ops['yrange'][1], ops['xrange'][0]:ops['xrange'][1]]
+        weights = 0.1 + np.clip(
+            (mean_img - np.percentile(mean_img, 1)) /
+            (np.percentile(mean_img, 99) - np.percentile(mean_img, 1)), 0, 1)
+    elif ops["anatomical_only"] == 3:
+        if "meanImgE" in ops:
+            img = ops["meanImgE"][ops["yrange"][0]:ops["yrange"][1],
+                                  ops["xrange"][0]:ops["xrange"][1]]
         else:
             img = mean_img
-            print('no enhanced mean image, using mean image instead')
-        weights = 0.1 + np.clip((mean_img - np.percentile(mean_img,1)) / 
-                                (np.percentile(mean_img,99) - np.percentile(mean_img,1)), 0, 1)
+            print("no enhanced mean image, using mean image instead")
+        weights = 0.1 + np.clip(
+            (mean_img - np.percentile(mean_img, 1)) /
+            (np.percentile(mean_img, 99) - np.percentile(mean_img, 1)), 0, 1)
     else:
         img = max_proj.copy()
         weights = max_proj
 
     t0 = time.time()
     if diameter is not None:
-        if isinstance(diameter, (list, np.ndarray)) and len(ops['diameter'])>1:
+        if isinstance(diameter, (list, np.ndarray)) and len(ops["diameter"]) > 1:
             rescale = diameter[1] / diameter[0]
-            img = cv2.resize(img, (Lxc, int(Lyc*rescale)))
+            img = cv2.resize(img, (Lxc, int(Lyc * rescale)))
         else:
             rescale = 1.0
             diameter = [diameter, diameter]
         if diameter[1] > 0:
-            print("!NOTE! diameter set to %0.2f for cell detection with cellpose"%diameter[1])
+            print("!NOTE! diameter set to %0.2f for cell detection with cellpose" %
+                  diameter[1])
         else:
-            print("!NOTE! diameter set to 0 or None, diameter will be estimated by cellpose")
+            print(
+                "!NOTE! diameter set to 0 or None, diameter will be estimated by cellpose"
+            )
     else:
-        print("!NOTE! diameter set to 0 or None, diameter will be estimated by cellpose")
+        print(
+            "!NOTE! diameter set to 0 or None, diameter will be estimated by cellpose")
 
-    if ops.get('spatial_hp_cp', 0):
+    if ops.get("spatial_hp_cp", 0):
         img = np.clip(normalize99(img), 0, 1)
-        img -= gaussian_filter(img, diameter[1]*ops['spatial_hp_cp'])
+        img -= gaussian_filter(img, diameter[1] * ops["spatial_hp_cp"])
 
-    masks, centers, median_diam, mask_diams = roi_detect(img, diameter=diameter[1],
-                                                         flow_threshold=ops['flow_threshold'],
-                                                         cellprob_threshold=ops['cellprob_threshold'],
-                                                         pretrained_model=ops['pretrained_model'])
+    masks, centers, median_diam, mask_diams = roi_detect(
+        img, diameter=diameter[1], flow_threshold=ops["flow_threshold"],
+        cellprob_threshold=ops["cellprob_threshold"],
+        pretrained_model=ops["pretrained_model"])
     if rescale != 1.0:
         masks = cv2.resize(masks, (Lxc, Lyc), interpolation=cv2.INTER_NEAREST)
         img = cv2.resize(img, (Lxc, Lyc))
     stats = masks_to_stats(masks, weights)
-    print('Detected %d ROIs, %0.2f sec' % (len(stats), time.time() - t0))
-    
+    print("Detected %d ROIs, %0.2f sec" % (len(stats), time.time() - t0))
+
     new_ops = {
-            'diameter': median_diam,
-            'max_proj': max_proj,
-            'Vmax': 0,
-            'ihop': 0,
-            'Vsplit': 0,
-            'Vcorr': img,
-            'Vmap': 0,
-            'spatscale_pix': 0
-        }
+        "diameter": median_diam,
+        "max_proj": max_proj,
+        "Vmax": 0,
+        "ihop": 0,
+        "Vsplit": 0,
+        "Vcorr": img,
+        "Vmap": 0,
+        "spatscale_pix": 0
+    }
     ops.update(new_ops)
 
     return stats
 
+
 # def run_assist():
 #     nmasks, diam = 0, None
-#     if anatomical: 
+#     if anatomical:
 #         try:
-#             print('>>>> CELLPOSE estimating spatial scale and masks as seeds for functional algorithm')
-#             from . import anatomical 
+#             print(">>>> CELLPOSE estimating spatial scale and masks as seeds for functional algorithm")
+#             from . import anatomical
 #             mproj = np.log(np.maximum(1e-3, max_proj / np.maximum(1e-3, mean_img)))
-#             masks, centers, diam, mask_diams = anatomical.roi_detect(mproj)  
-#             nmasks = masks.max()    
+#             masks, centers, diam, mask_diams = anatomical.roi_detect(mproj)
+#             nmasks = masks.max()
 #         except:
-#             print('ERROR importing or running cellpose, continuing without anatomical estimates')
+#             print("ERROR importing or running cellpose, continuing without anatomical estimates")
 #         if tj < nmasks:
 #             yi, xi = centers[tj]
 #             ls = mask_diams[tj]
@@ -230,9 +246,5 @@ def select_rois(ops: Dict[str, Any], mov: np.ndarray,
 # if nmasks > 0:
 #         stats = anatomical.refine_masks(stats, patches, seeds, diam, Lyc, Lxc)
 #         for stat in stats:
-#             if stat['anatomical']:
-#                 stat['lam'] *= sdmov[stat['ypix'], stat['xpix']]
-    
-
-    
-
+#             if stat["anatomical"]:
+#                 stat["lam"] *= sdmov[stat["ypix"], stat["xpix"]]
diff --git a/suite2p/detection/chan2detect.py b/suite2p/detection/chan2detect.py
index d282d2b8b..28f872244 100644
--- a/suite2p/detection/chan2detect.py
+++ b/suite2p/detection/chan2detect.py
@@ -1,107 +1,120 @@
 import numpy as np
 from scipy.ndimage import gaussian_filter
-from ..extraction import masks 
+from ..extraction import masks
 from . import utils
-
-'''
+"""
 identify cells with channel 2 brightness (aka red cells)
 
 main function is detect
-takes from ops: 'meanImg', 'meanImg_chan2', 'Ly', 'Lx'
-takes from stat: 'ypix', 'xpix', 'lam'
-'''
+takes from ops: "meanImg", "meanImg_chan2", "Ly", "Lx"
+takes from stat: "ypix", "xpix", "lam"
+"""
+
 
-def quadrant_mask(Ly,Lx,ny,nx,sT):
-    mask = np.zeros((Ly,Lx), np.float32)
-    mask[np.ix_(ny,nx)] = 1
+def quadrant_mask(Ly, Lx, ny, nx, sT):
+    mask = np.zeros((Ly, Lx), np.float32)
+    mask[np.ix_(ny, nx)] = 1
     mask = gaussian_filter(mask, sT)
     return mask
 
+
 def correct_bleedthrough(Ly, Lx, nblks, mimg, mimg2):
     # subtract bleedthrough of green into red channel
     # non-rigid regression with nblks x nblks pieces
-    sT = np.round((Ly + Lx) / (nblks*2) * 0.25)
+    sT = np.round((Ly + Lx) / (nblks * 2) * 0.25)
     mask = np.zeros((Ly, Lx, nblks, nblks), np.float32)
     weights = np.zeros((nblks, nblks), np.float32)
-    yb = np.linspace(0, Ly, nblks+1).astype(int)
-    xb = np.linspace(0, Lx, nblks+1).astype(int)
+    yb = np.linspace(0, Ly, nblks + 1).astype(int)
+    xb = np.linspace(0, Lx, nblks + 1).astype(int)
     for iy in range(nblks):
         for ix in range(nblks):
-            ny = np.arange(yb[iy], yb[iy+1]).astype(int)
-            nx = np.arange(xb[ix], xb[ix+1]).astype(int)
-            mask[:,:,iy,ix] = quadrant_mask(Ly, Lx, ny, nx, sT)
-            x  = mimg[np.ix_(ny,nx)].flatten()
-            x2  = mimg2[np.ix_(ny,nx)].flatten()
+            ny = np.arange(yb[iy], yb[iy + 1]).astype(int)
+            nx = np.arange(xb[ix], xb[ix + 1]).astype(int)
+            mask[:, :, iy, ix] = quadrant_mask(Ly, Lx, ny, nx, sT)
+            x = mimg[np.ix_(ny, nx)].flatten()
+            x2 = mimg2[np.ix_(ny, nx)].flatten()
             # predict chan2 from chan1
             a = (x * x2).sum() / (x * x).sum()
-            weights[iy,ix] = a
-    mask /= mask.sum(axis=-1).sum(axis=-1)[:,:,np.newaxis,np.newaxis]
+            weights[iy, ix] = a
+    mask /= mask.sum(axis=-1).sum(axis=-1)[:, :, np.newaxis, np.newaxis]
     mask *= weights
-    mask *= mimg[:,:,np.newaxis,np.newaxis]
+    mask *= mimg[:, :, np.newaxis, np.newaxis]
     mimg2 -= mask.sum(axis=-1).sum(axis=-1)
     mimg2 = np.maximum(0, mimg2)
     return mimg2
 
+
 def intensity_ratio(ops, stats):
     """ compute pixels in cell and in area around cell (including overlaps)
         (exclude pixels from other cells) """
-    Ly, Lx = ops['Ly'], ops['Lx']
-    cell_pix = masks.create_cell_pix(stats, Ly=ops['Ly'], Lx=ops['Lx'])
-    cell_masks0 = [masks.create_cell_mask(stat, Ly=ops['Ly'], Lx=ops['Lx'], allow_overlap=ops['allow_overlap']) for stat in stats]
+    Ly, Lx = ops["Ly"], ops["Lx"]
+    cell_pix = masks.create_cell_pix(stats, Ly=ops["Ly"], Lx=ops["Lx"])
+    cell_masks0 = [
+        masks.create_cell_mask(stat, Ly=ops["Ly"], Lx=ops["Lx"],
+                               allow_overlap=ops["allow_overlap"]) for stat in stats
+    ]
     neuropil_ipix = masks.create_neuropil_masks(
-        ypixs=[stat['ypix'] for stat in stats],
-        xpixs=[stat['xpix'] for stat in stats],
+        ypixs=[stat["ypix"] for stat in stats],
+        xpixs=[stat["xpix"] for stat in stats],
         cell_pix=cell_pix,
-        inner_neuropil_radius=ops['inner_neuropil_radius'],
-        min_neuropil_pixels=ops['min_neuropil_pixels'],
+        inner_neuropil_radius=ops["inner_neuropil_radius"],
+        min_neuropil_pixels=ops["min_neuropil_pixels"],
     )
     cell_masks = np.zeros((len(stats), Ly * Lx), np.float32)
     neuropil_masks = np.zeros((len(stats), Ly * Lx), np.float32)
-    for cell_mask, cell_mask0, neuropil_mask, neuropil_mask0 in zip(cell_masks, cell_masks0, neuropil_masks, neuropil_ipix):
+    for cell_mask, cell_mask0, neuropil_mask, neuropil_mask0 in zip(
+            cell_masks, cell_masks0, neuropil_masks, neuropil_ipix):
         cell_mask[cell_mask0[0]] = cell_mask0[1]
         neuropil_mask[neuropil_mask0.astype(np.int64)] = 1. / len(neuropil_mask0)
 
-    mimg2 = ops['meanImg_chan2']
+    mimg2 = ops["meanImg_chan2"]
     inpix = cell_masks @ mimg2.flatten()
     extpix = neuropil_masks @ mimg2.flatten()
     inpix = np.maximum(1e-3, inpix)
     redprob = inpix / (inpix + extpix)
-    redcell = redprob > ops['chan2_thres']
+    redcell = redprob > ops["chan2_thres"]
     return np.stack((redcell, redprob), axis=-1)
 
+
 def cellpose_overlap(stats, mimg2):
-    from . import anatomical 
+    from . import anatomical
     masks = anatomical.roi_detect(mimg2)[0]
     Ly, Lx = masks.shape
-    redstats = np.zeros((len(stats),2), np.float32) #changed the size of preallocated space
+    redstats = np.zeros((len(stats), 2),
+                        np.float32)  #changed the size of preallocated space
     for i in range(len(stats)):
         smask = np.zeros((Ly, Lx), np.uint16)
-        ypix0, xpix0= stats[i]['ypix'], stats[i]['xpix']
+        ypix0, xpix0 = stats[i]["ypix"], stats[i]["xpix"]
         smask[ypix0, xpix0] = 1
         ious = utils.mask_ious(masks, smask)[0]
         iou = ious.max()
-        redstats[i,] = np.array([iou>0.5, iou]) #this had the wrong dimension
+        redstats[
+            i,
+        ] = np.array([iou > 0.5, iou])  #this had the wrong dimension
     return redstats
 
+
 def detect(ops, stats):
-    mimg = ops['meanImg'].copy()
-    mimg2 = ops['meanImg_chan2'].copy()
+    mimg = ops["meanImg"].copy()
+    mimg2 = ops["meanImg_chan2"].copy()
 
     # subtract bleedthrough of green into red channel
     # non-rigid regression with nblks x nblks pieces
     nblks = 3
-    Ly, Lx = ops['Ly'], ops['Lx']
-    ops['meanImg_chan2_corrected'] = correct_bleedthrough(Ly, Lx, nblks, mimg, mimg2)
+    Ly, Lx = ops["Ly"], ops["Lx"]
+    ops["meanImg_chan2_corrected"] = correct_bleedthrough(Ly, Lx, nblks, mimg, mimg2)
 
     redstats = None
-    if ops.get('anatomical_red', True):
+    if ops.get("anatomical_red", True):
         try:
-            print('>>>> CELLPOSE estimating masks in anatomical channel')
+            print(">>>> CELLPOSE estimating masks in anatomical channel")
             redstats = cellpose_overlap(stats, mimg2)
         except:
-            print('ERROR importing or running cellpose, continuing without anatomical estimates')
-            
+            print(
+                "ERROR importing or running cellpose, continuing without anatomical estimates"
+            )
+
     if redstats is None:
         redstats = intensity_ratio(ops, stats)
-        
+
     return ops, redstats
diff --git a/suite2p/detection/denoise.py b/suite2p/detection/denoise.py
index 15823139c..8ea8871b3 100644
--- a/suite2p/detection/denoise.py
+++ b/suite2p/detection/denoise.py
@@ -15,22 +15,25 @@ def pca_denoise(mov: np.ndarray, block_size: List, n_comps_frac: float):
 
     nblocks = len(yblock)
     Lyb, Lxb = block_size
-    n_comps = int(min(min(Lyb*Lxb,nframes), min(Lyb, Lxb) * n_comps_frac))
-    maskMul = spatial_taper(Lyb//4, Lyb, Lxb)
+    n_comps = int(min(min(Lyb * Lxb, nframes), min(Lyb, Lxb) * n_comps_frac))
+    maskMul = spatial_taper(Lyb // 4, Lyb, Lxb)
     norm = np.zeros((Ly, Lx), np.float32)
     reconstruction = np.zeros_like(mov)
-    block_re = np.zeros((nblocks, nframes, Lyb*Lxb))
+    block_re = np.zeros((nblocks, nframes, Lyb * Lxb))
     for i in range(nblocks):
-        block = mov[:, yblock[i][0] : yblock[i][-1], xblock[i][0] : xblock[i][-1]].reshape(-1, Lyb*Lxb)
+        block = mov[:, yblock[i][0]:yblock[i][-1],
+                    xblock[i][0]:xblock[i][-1]].reshape(-1, Lyb * Lxb)
         model = PCA(n_components=n_comps, random_state=0).fit(block)
         block_re[i] = (block @ model.components_.T) @ model.components_
-        norm[yblock[i][0] : yblock[i][-1], xblock[i][0] : xblock[i][-1]] += maskMul
+        norm[yblock[i][0]:yblock[i][-1], xblock[i][0]:xblock[i][-1]] += maskMul
 
     block_re = block_re.reshape(nblocks, nframes, Lyb, Lxb)
     block_re *= maskMul
     for i in range(nblocks):
-        reconstruction[:, yblock[i][0] : yblock[i][-1], xblock[i][0] : xblock[i][-1]] += block_re[i]
+        reconstruction[:, yblock[i][0]:yblock[i][-1],
+                       xblock[i][0]:xblock[i][-1]] += block_re[i]
     reconstruction /= norm
-    print('Binned movie denoised (for cell detection only) in %0.2f sec.' % (time.time() - t0))
+    print("Binned movie denoised (for cell detection only) in %0.2f sec." %
+          (time.time() - t0))
     reconstruction += mov_mean
     return reconstruction
diff --git a/suite2p/detection/detect.py b/suite2p/detection/detect.py
index 5ff3259b2..f7809feb4 100644
--- a/suite2p/detection/detect.py
+++ b/suite2p/detection/detect.py
@@ -10,77 +10,81 @@
 from ..classification import classify, user_classfile
 from .. import default_ops
 
+
 def detect(ops, classfile=None):
-	
-	t0 = time.time()
-	bin_size = int(max(1, ops['nframes'] // ops['nbinned'], np.round(ops['tau'] * ops['fs'])))
-	print('Binning movie in chunks of length %2.2d' % bin_size)
-	with BinaryFile(read_filename=ops['reg_file'], Ly=ops['Ly'], Lx=ops['Lx']) as f:
-		mov = f.bin_movie(
-			bin_size=bin_size,
-			bad_frames=ops.get('badframes'),
-			y_range=ops['yrange'],
-			x_range=ops['xrange'],
-		)
-		print('Binned movie [%d,%d,%d] in %0.2f sec.' % (mov.shape[0], mov.shape[1], mov.shape[2], time.time() - t0))
-	
-		ops, stat = detection_wrapper(f, mov=mov, ops=ops, classfile=classfile)
 
-	return ops, stat
+    t0 = time.time()
+    bin_size = int(
+        max(1, ops["nframes"] // ops["nbinned"], np.round(ops["tau"] * ops["fs"])))
+    print("Binning movie in chunks of length %2.2d" % bin_size)
+    with BinaryFile(filename=ops["reg_file"], Ly=ops["Ly"], Lx=ops["Lx"]) as f:
+        mov = f.bin_movie(
+            bin_size=bin_size,
+            bad_frames=ops.get("badframes"),
+            y_range=ops["yrange"],
+            x_range=ops["xrange"],
+        )
+        print("Binned movie [%d,%d,%d] in %0.2f sec." %
+              (mov.shape[0], mov.shape[1], mov.shape[2], time.time() - t0))
+
+        ops, stat = detection_wrapper(f, mov=mov, ops=ops, classfile=classfile)
+
+    return ops, stat
+
 
 def bin_movie(f_reg, bin_size, yrange=None, xrange=None, badframes=None):
-	""" bin registered movie """
-	n_frames = f_reg.shape[0]
-	good_frames = ~badframes if badframes is not None else np.ones(n_frames, dtype=bool)
-	batch_size = min(good_frames.sum(), 500)
-	Lyc = yrange[1] - yrange[0]
-	Lxc = xrange[1] - xrange[0]
-
-	# Number of binned frames is rounded down when binning frames 
-	num_binned_frames = n_frames//bin_size
-	mov = np.zeros((num_binned_frames, Lyc, Lxc), np.float32)
-	curr_bin_number = 0
-	t0 = time.time()
-
-	# Iterate over n_frames to maintain binning over TIME
-	for k in np.arange(0, n_frames, batch_size):
-		data = f_reg[k : min(k + batch_size, n_frames)]
-
-		# exclude badframes
-		good_indices = good_frames[k : min(k + batch_size, n_frames)]
-		if good_indices.mean() > 0.5:
-			data = data[good_indices]
-
-		# crop to valid region
-		if yrange is not None and xrange is not None:
-			data = data[:, slice(*yrange), slice(*xrange)]
-
-		# bin in time
-		if data.shape[0] > bin_size:
-			# Downsample by binning via reshaping and taking mean of each bin 
-			# only if current batch size exceeds or matches bin_size 
-			n_d = data.shape[0]
-			data = data[:(n_d // bin_size) * bin_size]
-			data = data.reshape(-1, bin_size, Lyc, Lxc).astype(np.float32).mean(axis=1)
-		else:
-			# Current batch size is below bin_size (could have many bad frames in this batch)
-			# Downsample taking the mean of batch to get a single bin
-			data = data.mean(axis=0)[np.newaxis,:,:]
-		# Only fill in binned data if not exceeding the number of bins mov has
-		if mov.shape[0] > curr_bin_number: 
-			# Fill in binned data
-			n_bins = data.shape[0]
-			mov[curr_bin_number : curr_bin_number + n_bins] = data
-			curr_bin_number += n_bins
-
-	print('Binned movie of size [%d,%d,%d] created in %0.2f sec.' % (mov.shape[0], mov.shape[1], mov.shape[2], time.time() - t0))
-	return mov
-
-
-
-def detection_wrapper(f_reg, mov=None, yrange=None, xrange=None, 
-					  ops=default_ops(), classfile=None):
-	"""
+    """ bin registered movie """
+    n_frames = f_reg.shape[0]
+    good_frames = ~badframes if badframes is not None else np.ones(n_frames, dtype=bool)
+    batch_size = min(good_frames.sum(), 500)
+    Lyc = yrange[1] - yrange[0]
+    Lxc = xrange[1] - xrange[0]
+
+    # Number of binned frames is rounded down when binning frames
+    num_binned_frames = n_frames // bin_size
+    mov = np.zeros((num_binned_frames, Lyc, Lxc), np.float32)
+    curr_bin_number = 0
+    t0 = time.time()
+
+    # Iterate over n_frames to maintain binning over TIME
+    for k in np.arange(0, n_frames, batch_size):
+        data = f_reg[k:min(k + batch_size, n_frames)]
+
+        # exclude badframes
+        good_indices = good_frames[k:min(k + batch_size, n_frames)]
+        if good_indices.mean() > 0.5:
+            data = data[good_indices]
+
+        # crop to valid region
+        if yrange is not None and xrange is not None:
+            data = data[:, slice(*yrange), slice(*xrange)]
+
+        # bin in time
+        if data.shape[0] > bin_size:
+            # Downsample by binning via reshaping and taking mean of each bin
+            # only if current batch size exceeds or matches bin_size
+            n_d = data.shape[0]
+            data = data[:(n_d // bin_size) * bin_size]
+            data = data.reshape(-1, bin_size, Lyc, Lxc).astype(np.float32).mean(axis=1)
+        else:
+            # Current batch size is below bin_size (could have many bad frames in this batch)
+            # Downsample taking the mean of batch to get a single bin
+            data = data.mean(axis=0)[np.newaxis, :, :]
+        # Only fill in binned data if not exceeding the number of bins mov has
+        if mov.shape[0] > curr_bin_number:
+            # Fill in binned data
+            n_bins = data.shape[0]
+            mov[curr_bin_number:curr_bin_number + n_bins] = data
+            curr_bin_number += n_bins
+
+    print("Binned movie of size [%d,%d,%d] created in %0.2f sec." %
+          (mov.shape[0], mov.shape[1], mov.shape[2], time.time() - t0))
+    return mov
+
+
+def detection_wrapper(f_reg, mov=None, yrange=None, xrange=None, ops=default_ops(),
+                      classfile=None):
+    """
 	Main detection function. 
 
 	Identifies ROIs. 
@@ -88,7 +92,7 @@ def detection_wrapper(f_reg, mov=None, yrange=None, xrange=None,
 	Parameters
 	----------------
 
-	f_reg : np.ndarray or io.BinaryRWFile,
+	f_reg : np.ndarray or io.BinaryWFile,
 		n_frames x Ly x Lx
 
 	mov : ndarray (t x Lyc x Lxc)
@@ -110,130 +114,137 @@ def detection_wrapper(f_reg, mov=None, yrange=None, xrange=None,
 
 	ops : dictionary or list of dicts
 		
-	stat : dictionary 'ypix', 'xpix', 'lam'
+	stat : dictionary "ypix", "xpix", "lam"
 		Dictionary containing statistics for ROIs
 
 
 	"""
-	n_frames, Ly, Lx = f_reg.shape
-	yrange = ops.get('yrange', [0, Ly]) if yrange is None else yrange
-	xrange = ops.get('xrange', [0, Lx]) if xrange is None else xrange
-	
-	if mov is None:
-		bin_size = int(max(1, n_frames // ops['nbinned'], np.round(ops['tau'] * ops['fs'])))
-		print('Binning movie in chunks of length %2.2d' % bin_size)
-		mov = bin_movie(f_reg, bin_size, yrange=yrange, 
-						xrange=xrange, badframes=ops.get('badframes', None))
-	else:    
-		if mov.shape[1] != yrange[-1] - yrange[0]:
-			raise ValueError('mov.shape[1] is not same size as yrange')
-		elif mov.shape[2] != xrange[-1] - xrange[0]:
-			raise ValueError('mov.shape[2] is not same size as xrange')
-		
-	if ops.get('inverted_activity', False):
-		mov -= mov.min()
-		mov *= -1
-		mov -= mov.min()
-
-	if ops.get('denoise', 1):
-		mov = pca_denoise(mov, block_size=[ops['block_size'][0]//2, ops['block_size'][1]//2],
-							n_comps_frac = 0.5)
-
-	if ops.get('anatomical_only', 0):
-		try:
-			from . import anatomical
-			CELLPOSE_INSTALLED = True
-		except Exception as e:
-			print('Warning: cellpose did not import')
-			print(e)
-			print('cannot use anatomical mode, but otherwise suite2p will run normally')
-			CELLPOSE_INSTALLED = False
-		if not CELLPOSE_INSTALLED:
-			print('~~~ tried to import cellpose to run anatomical but failed, install with: ~~~')
-			print('$ pip install cellpose')
-		else:
-			print('>>>> CELLPOSE finding masks in ' + ['max_proj / mean_img', 'mean_img', 'enhanced_mean_img', 'max_proj'][int(ops['anatomical_only'])-1])
-			stat = anatomical.select_rois(
-						ops=ops,
-						mov=mov,
-						diameter=ops.get('diameter', None))
-	else:            
-		stat = select_rois(
-			ops=ops,
-			mov=mov,
-			sparse_mode=ops['sparse_mode'],
-			classfile=classfile,
-		)
-
-	ymin = int(yrange[0])
-	xmin = int(xrange[0])
-	if len(stat) > 0:
-		for s in stat:
-			s['ypix'] += ymin
-			s['xpix'] += xmin
-			s['med'][0] += ymin
-			s['med'][1] += xmin    
-		
-		if ops['preclassify'] > 0:
-			if classfile is None:
-				print(f'NOTE: Applying user classifier at {str(user_classfile)}')
-				classfile = user_classfile
-
-			stat =  roi_stats(stat, Ly, Lx, aspect=ops.get('aspect', None), 
-							diameter=ops.get('diameter', None), do_crop=ops.get('soma_crop', 1))
-			if len(stat) == 0:
-				iscell = np.zeros((0, 2))
-			else:
-				iscell = classify(stat=stat, classfile=classfile)
-			np.save(Path(ops['save_path']).joinpath('iscell.npy'), iscell)
-			ic = (iscell[:,0]>ops['preclassify']).flatten().astype('bool')
-			stat = stat[ic]
-			print('Preclassify threshold %0.2f, %d ROIs removed' % (ops['preclassify'], (~ic).sum()))
-		
-		stat = roi_stats(stat, Ly, Lx, aspect=ops.get('aspect', None), 
-						diameter=ops.get('diameter', None), 
-						max_overlap=ops['max_overlap'], 
-						do_crop=ops.get('soma_crop', 1))
-		print('After removing overlaps, %d ROIs remain' % (len(stat)))
-
-	# if second channel, detect bright cells in second channel
-	if 'meanImg_chan2' in ops:
-		if 'chan2_thres' not in ops:
-			ops['chan2_thres'] = 0.65
-		ops, redcell = chan2detect.detect(ops, stat)
-		np.save(Path(ops['save_path']).joinpath('redcell.npy'), redcell)
-
-	return ops, stat
-
-def select_rois(ops: Dict[str, Any], mov: np.ndarray, 
-				sparse_mode: bool = True,
-				classfile: Path = None):
-	
-	t0 = time.time()
-	if sparse_mode:
-		ops.update({'Lyc': mov.shape[1], 'Lxc': mov.shape[2]})
-		new_ops, stat = sparsedetect.sparsery(
-			mov=mov,
-			high_pass=ops['high_pass'],
-			neuropil_high_pass=ops['spatial_hp_detect'],
-			batch_size=ops['batch_size'],
-			spatial_scale=ops['spatial_scale'],
-			threshold_scaling=ops['threshold_scaling'],
-			max_iterations=250 * ops['max_iterations'],
-			percentile=ops.get('active_percentile', 0.0),
-		)
-		ops.update(new_ops)
-	else:
-		ops, stat = sourcery.sourcery(mov=mov, ops=ops)
-
-	print('Detected %d ROIs, %0.2f sec' % (len(stat), time.time() - t0))
-	stat = np.array(stat)
-	
-	if len(stat)==0:
-		raise ValueError("no ROIs were found -- check registered binary and maybe change spatial scale")
-		
-	# add ROI stat to stat
-	#stat = roi_stats(stat, dy, dx, Ly, Lx, max_overlap=max_overlap, do_crop=do_crop)
-
-	return stat
-
+    n_frames, Ly, Lx = f_reg.shape
+    yrange = ops.get("yrange", [0, Ly]) if yrange is None else yrange
+    xrange = ops.get("xrange", [0, Lx]) if xrange is None else xrange
+
+    if mov is None:
+        bin_size = int(
+            max(1, n_frames // ops["nbinned"], np.round(ops["tau"] * ops["fs"])))
+        print("Binning movie in chunks of length %2.2d" % bin_size)
+        mov = bin_movie(f_reg, bin_size, yrange=yrange, xrange=xrange,
+                        badframes=ops.get("badframes", None))
+    else:
+        if mov.shape[1] != yrange[-1] - yrange[0]:
+            raise ValueError("mov.shape[1] is not same size as yrange")
+        elif mov.shape[2] != xrange[-1] - xrange[0]:
+            raise ValueError("mov.shape[2] is not same size as xrange")
+
+    if ops.get("inverted_activity", False):
+        mov -= mov.min()
+        mov *= -1
+        mov -= mov.min()
+
+    if ops.get("denoise", 1):
+        mov = pca_denoise(
+            mov, block_size=[ops["block_size"][0] // 2, ops["block_size"][1] // 2],
+            n_comps_frac=0.5)
+
+    if ops.get("anatomical_only", 0):
+        try:
+            from . import anatomical
+            CELLPOSE_INSTALLED = True
+        except Exception as e:
+            print("Warning: cellpose did not import")
+            print(e)
+            print("cannot use anatomical mode, but otherwise suite2p will run normally")
+            CELLPOSE_INSTALLED = False
+        if not CELLPOSE_INSTALLED:
+            print(
+                "~~~ tried to import cellpose to run anatomical but failed, install with: ~~~"
+            )
+            print("$ pip install cellpose")
+        else:
+            print(">>>> CELLPOSE finding masks in " +
+                  ["max_proj / mean_img", "mean_img", "enhanced_mean_img", "max_proj"][
+                      int(ops["anatomical_only"]) - 1])
+            stat = anatomical.select_rois(ops=ops, mov=mov,
+                                          diameter=ops.get("diameter", None))
+    else:
+        stat = select_rois(
+            ops=ops,
+            mov=mov,
+            sparse_mode=ops["sparse_mode"],
+            classfile=classfile,
+        )
+
+    ymin = int(yrange[0])
+    xmin = int(xrange[0])
+    if len(stat) > 0:
+        for s in stat:
+            s["ypix"] += ymin
+            s["xpix"] += xmin
+            s["med"][0] += ymin
+            s["med"][1] += xmin
+
+        if ops["preclassify"] > 0:
+            if classfile is None:
+                print(f"NOTE: Applying user classifier at {str(user_classfile)}")
+                classfile = user_classfile
+
+            stat = roi_stats(stat, Ly, Lx, aspect=ops.get("aspect", None),
+                             diameter=ops.get("diameter",
+                                              None), do_crop=ops.get("soma_crop", 1))
+            if len(stat) == 0:
+                iscell = np.zeros((0, 2))
+            else:
+                iscell = classify(stat=stat, classfile=classfile)
+            np.save(Path(ops["save_path"]).joinpath("iscell.npy"), iscell)
+            ic = (iscell[:, 0] > ops["preclassify"]).flatten().astype("bool")
+            stat = stat[ic]
+            print("Preclassify threshold %0.2f, %d ROIs removed" % (ops["preclassify"],
+                                                                    (~ic).sum()))
+
+        stat = roi_stats(stat, Ly, Lx, aspect=ops.get("aspect", None),
+                         diameter=ops.get("diameter",
+                                          None), max_overlap=ops["max_overlap"],
+                         do_crop=ops.get("soma_crop", 1))
+        print("After removing overlaps, %d ROIs remain" % (len(stat)))
+
+    # if second channel, detect bright cells in second channel
+    if "meanImg_chan2" in ops:
+        if "chan2_thres" not in ops:
+            ops["chan2_thres"] = 0.65
+        ops, redcell = chan2detect.detect(ops, stat)
+        np.save(Path(ops["save_path"]).joinpath("redcell.npy"), redcell)
+
+    return ops, stat
+
+
+def select_rois(ops: Dict[str, Any], mov: np.ndarray, sparse_mode: bool = True,
+                classfile: Path = None):
+
+    t0 = time.time()
+    if sparse_mode:
+        ops.update({"Lyc": mov.shape[1], "Lxc": mov.shape[2]})
+        new_ops, stat = sparsedetect.sparsery(
+            mov=mov,
+            high_pass=ops["high_pass"],
+            neuropil_high_pass=ops["spatial_hp_detect"],
+            batch_size=ops["batch_size"],
+            spatial_scale=ops["spatial_scale"],
+            threshold_scaling=ops["threshold_scaling"],
+            max_iterations=250 * ops["max_iterations"],
+            percentile=ops.get("active_percentile", 0.0),
+        )
+        ops.update(new_ops)
+    else:
+        ops, stat = sourcery.sourcery(mov=mov, ops=ops)
+
+    print("Detected %d ROIs, %0.2f sec" % (len(stat), time.time() - t0))
+    stat = np.array(stat)
+
+    if len(stat) == 0:
+        raise ValueError(
+            "no ROIs were found -- check registered binary and maybe change spatial scale"
+        )
+
+    # add ROI stat to stat
+    #stat = roi_stats(stat, dy, dx, Ly, Lx, max_overlap=max_overlap, do_crop=do_crop)
+
+    return stat
diff --git a/suite2p/detection/metrics.py b/suite2p/detection/metrics.py
index fe22388bb..0fd5d120e 100644
--- a/suite2p/detection/metrics.py
+++ b/suite2p/detection/metrics.py
@@ -6,6 +6,7 @@
 from .denoise import pca_denoise
 from ..io import BinaryFile
 
+
 def compute_gt_matches(img, masks, stat_func, ops=None, reg_file=None, threshold=0.5):
     """ anatomical img and masks matched to functional ROIs in stat_func """
     Ly, Lx = masks.shape
@@ -18,124 +19,134 @@ def compute_gt_matches(img, masks, stat_func, ops=None, reg_file=None, threshold
 
     return stat_anat, iorig, iou, func_ids, overlaps
 
+
 def match_func_anat(stat_func, stat_anat, Ly, Lx, threshold=0.5):
     """ match functional ROIs to anatomical ROIs by correlation"""
-    iou = np.zeros((len(stat_anat), len(stat_func)))    
+    iou = np.zeros((len(stat_anat), len(stat_func)))
     ly = 15
-    for i,sf in enumerate(stat_func):
-        if sf['ypix'].size < 20:
+    for i, sf in enumerate(stat_func):
+        if sf["ypix"].size < 20:
             continue
-        ypix, xpix, lam = sf['ypix'].copy(), sf['xpix'].copy(), sf['lam'].copy()
+        ypix, xpix, lam = sf["ypix"].copy(), sf["xpix"].copy(), sf["lam"].copy()
         lam /= (lam**2).sum()**0.5
         # box around ROI
-        ymed, xmed = sf['med'][0], sf['med'][1]
-        inds = (slice(max(0, ymed-ly), min(ymed+ly, Ly)),
-                slice(max(0, xmed-ly), min(xmed+ly, Lx)))
-        mf = np.zeros((Ly,Lx), np.float32)
+        ymed, xmed = sf["med"][0], sf["med"][1]
+        inds = (slice(max(0, ymed - ly),
+                      min(ymed + ly, Ly)), slice(max(0, xmed - ly), min(xmed + ly, Lx)))
+        mf = np.zeros((Ly, Lx), np.float32)
         mf[ypix, xpix] = lam
-        mfc = mf[inds].flatten() 
+        mfc = mf[inds].flatten()
         mfc /= (mfc**2).sum()**0.5
-    
+
         # matched anatomical masks (will not compute IOU for all masks)
         for j, sa in enumerate(stat_anat):
-            ypix_a, xpix_a = sa['ypix'], sa['xpix']
-            if (np.logical_and(ypix_a > inds[0].start, ypix_a < inds[0].stop).sum()>0 and
-                np.logical_and(xpix_a > inds[1].start, xpix_a < inds[1].stop).sum()>0):
-                lam_a = sa['lam'].copy()
+            ypix_a, xpix_a = sa["ypix"], sa["xpix"]
+            if (np.logical_and(ypix_a > inds[0].start, ypix_a < inds[0].stop).sum() > 0
+                    and np.logical_and(xpix_a > inds[1].start, xpix_a
+                                       < inds[1].stop).sum() > 0):
+                lam_a = sa["lam"].copy()
                 lam_a /= (lam_a**2).sum()**0.5
-                ma = np.zeros((Ly,Lx), np.float32)
+                ma = np.zeros((Ly, Lx), np.float32)
                 ma[ypix_a, xpix_a] = lam_a
-                mac = ma[inds].flatten() 
+                mac = ma[inds].flatten()
                 mac /= ((mac**2).sum()**0.5 + 1e-10)
                 iou[j, i] = (mac * mfc).sum()
-        if i%1000==0:
-            print('%d ROIs processed'%i)
-    print('%d ROIs processed'%i)
-    
+        if i % 1000 == 0:
+            print("%d ROIs processed" % i)
+    print("%d ROIs processed" % i)
+
     n_true = len(stat_anat)
     n_pred = len(stat_func)
     iout, preds = match_masks(iou)
-    tp = (iout>threshold).sum()
-    print((iout>threshold).sum())
+    tp = (iout > threshold).sum()
+    print((iout > threshold).sum())
     fn = n_true - tp
     fp = n_pred - tp
-    ap = tp/(fn+tp+fp)
-    print('TP: %d, FN: %d, FP: %d, AP: %0.3f'%
-          (tp, fn, fp, ap))
+    ap = tp / (fn + tp + fp)
+    print("TP: %d, FN: %d, FP: %d, AP: %0.3f" % (tp, fn, fp, ap))
 
     return iou, iout, preds, ap
 
+
 def extend_anatomical(img_anat, masks_anat, mov=None, ops=None, reg_file=None):
     if mov is None:
         if reg_file is None:
-            reg_file = ops['reg_file']
+            reg_file = ops["reg_file"]
 
-        bin_size = int(max(1, ops['nframes'] // ops['nbinned'], np.round(ops['tau'] * ops['fs'])))
+        bin_size = int(
+            max(1, ops["nframes"] // ops["nbinned"], np.round(ops["tau"] * ops["fs"])))
         t0 = time.time()
-        with BinaryFile(read_filename=reg_file, Ly=ops['Ly'], Lx=ops['Lx']) as f:
+        with BinaryFile(filename=reg_file, Ly=ops["Ly"], Lx=ops["Lx"]) as f:
             mov = f.bin_movie(
-                                bin_size=bin_size,
-                                bad_frames=ops.get('badframes'),
-                                y_range=ops['yrange'],
-                                x_range=ops['xrange'],
-                                )
-        print('Binned movie [%d,%d,%d] in %0.2f sec.' % (mov.shape[0], mov.shape[1], mov.shape[2], time.time() - t0))
+                bin_size=bin_size,
+                bad_frames=ops.get("badframes"),
+                y_range=ops["yrange"],
+                x_range=ops["xrange"],
+            )
+        print("Binned movie [%d,%d,%d] in %0.2f sec." %
+              (mov.shape[0], mov.shape[1], mov.shape[2], time.time() - t0))
     nt, Lyc, Lxc = mov.shape
-    
+
     if ops is not None:
         # process movie
-        mov = pca_denoise(mov, [ops['block_size'][0]//2, ops['block_size'][1]//2], 0.5)
-        mov = temporal_high_pass_filter(mov=mov, width=int(ops['high_pass']))
-        sdmov = standard_deviation_over_time(mov, batch_size=ops['batch_size'])
-        mov = neuropil_subtraction(mov=mov / sdmov, filter_size=ops['spatial_hp_detect'])  # subtract low-pass filtered movie
+        mov = pca_denoise(mov, [ops["block_size"][0] // 2, ops["block_size"][1] // 2],
+                          0.5)
+        mov = temporal_high_pass_filter(mov=mov, width=int(ops["high_pass"]))
+        sdmov = standard_deviation_over_time(mov, batch_size=ops["batch_size"])
+        mov = neuropil_subtraction(
+            mov=mov / sdmov,
+            filter_size=ops["spatial_hp_detect"])  # subtract low-pass filtered movie
     else:
-        ops = {'yrange': [0, Lyc], 'xrange': [0, Lxc]}
+        ops = {"yrange": [0, Lyc], "xrange": [0, Lxc]}
         sdmov = np.ones(mov.shape[1:])
 
-    redimg = img_anat[ops['yrange'][0] : ops['yrange'][-1], ops['xrange'][0] : ops['xrange'][-1]]
-    redmasks = masks_anat[ops['yrange'][0] : ops['yrange'][-1], ops['xrange'][0] : ops['xrange'][-1]]
+    redimg = img_anat[ops["yrange"][0]:ops["yrange"][-1],
+                      ops["xrange"][0]:ops["xrange"][-1]]
+    redmasks = masks_anat[ops["yrange"][0]:ops["yrange"][-1],
+                          ops["xrange"][0]:ops["xrange"][-1]]
     ly = 10
     stat_anat = []
     iorig = []
     for i in range(masks_anat.max()):
-        ypix, xpix = np.nonzero(redmasks==(i+1))
-        if ypix.size < 10: 
+        ypix, xpix = np.nonzero(redmasks == (i + 1))
+        if ypix.size < 10:
             continue
-            
+
         # create box around ROI to grow ROI
         ymed, xmed = int(np.median(ypix)), int(np.median(xpix))
-        inds = (slice(max(0, ymed-ly), min(ymed+ly, Lyc)), 
-                slice(max(0, xmed-ly), min(xmed+ly, Lxc)))
-        maskb = np.zeros((Lyc,Lxc), 'bool')
+        inds = (slice(max(0, ymed - ly),
+                      min(ymed + ly, Lyc)), slice(max(0, xmed - ly),
+                                                  min(xmed + ly, Lxc)))
+        maskb = np.zeros((Lyc, Lxc), "bool")
         maskb[ypix, xpix] = 1
         maskb = maskb[inds].astype(np.float32)
         maskb /= (maskb.sum())**0.5
         bx = mov[:, inds[0], inds[1]]
-        
+
         ### get activity mask
         # find active frames
         lam = redimg[ypix, xpix]
-        F = mov[:,ypix,xpix] @ lam #.sum(axis=1)
+        F = mov[:, ypix, xpix] @ lam  #.sum(axis=1)
         active_frames = F > np.percentile(F, 99)
         # activity of pixels in box on active_frames
         cc = bx[active_frames].sum(axis=0)
-        cc_threshold = max(0, cc.max()/5.0)
+        cc_threshold = max(0, cc.max() / 5.0)
         cc_mask = cc > cc_threshold
-        
+
         # get connected components
-        nb_components, output, stats, centroids = cv2.connectedComponentsWithStats((cc_mask).astype(np.uint8), 
-                                                                                connectivity=4)
-        npix = stats[1:,-1]
-        if (npix>15).sum()==0:
-            continue  
-        
+        nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(
+            (cc_mask).astype(np.uint8), connectivity=4)
+        npix = stats[1:, -1]
+        if (npix > 15).sum() == 0:
+            continue
+
         # get overlap of connected components with original mask, take one with largest overlap
-        iou = _intersection_over_union((maskb>0).astype(np.uint16), 
-                                    output.astype(np.uint16))[1, 1:]
-        max_label = np.nonzero(npix>15)[0][iou[npix>15].argmax()]
-        cc_mask = (output==(max_label+1))
+        iou = _intersection_over_union((maskb > 0).astype(np.uint16),
+                                       output.astype(np.uint16))[1, 1:]
+        max_label = np.nonzero(npix > 15)[0][iou[npix > 15].argmax()]
+        cc_mask = (output == (max_label + 1))
         cc[~cc_mask] = 0
-        
+
         # correlation of activity mask with original mask
         mfunc = cc.flatten() / ((cc**2).sum()**0.5)
         corr = (mfunc * maskb.flatten()).sum()
@@ -144,17 +155,13 @@ def extend_anatomical(img_anat, masks_anat, mov=None, ops=None, reg_file=None):
 
         # mask pix and weights
         ypix, xpix = np.nonzero(cc_mask)
-        ypix += max(0, ymed-ly)
-        xpix += max(0, xmed-ly)
+        ypix += max(0, ymed - ly)
+        xpix += max(0, xmed - ly)
         lam = cc[cc_mask] * sdmov[ypix, xpix]
         # ypix, xpix in full coordinates
-        ypix += ops['yrange'][0]
-        xpix += ops['xrange'][0]
-        stat_anat.append({'ypix': ypix, 'xpix': xpix, 'lam': lam})
+        ypix += ops["yrange"][0]
+        xpix += ops["xrange"][0]
+        stat_anat.append({"ypix": ypix, "xpix": xpix, "lam": lam})
         iorig.append(i)
-    
-    return stat_anat, iorig
-        
-
 
-        
\ No newline at end of file
+    return stat_anat, iorig
diff --git a/suite2p/detection/sourcery.py b/suite2p/detection/sourcery.py
index 144858162..dbea4b9c8 100644
--- a/suite2p/detection/sourcery.py
+++ b/suite2p/detection/sourcery.py
@@ -9,49 +9,51 @@
 from .stats import fitMVGaus
 from .utils import temporal_high_pass_filter, standard_deviation_over_time
 
+
 def getSVDdata(mov: np.ndarray, ops):
 
-    mov = temporal_high_pass_filter(mov, width=int(ops['high_pass']))
-    ops['max_proj'] = mov.max(axis=0)
+    mov = temporal_high_pass_filter(mov, width=int(ops["high_pass"]))
+    ops["max_proj"] = mov.max(axis=0)
     nbins, Lyc, Lxc = np.shape(mov)
 
-    sig = ops['diameter']/10. # PICK UP
+    sig = ops["diameter"] / 10.  # PICK UP
     for j in range(nbins):
-        mov[j,:,:] = gaussian_filter(mov[j,:,:], sig)
+        mov[j, :, :] = gaussian_filter(mov[j, :, :], sig)
 
     # compute noise variance across frames
-    sdmov = standard_deviation_over_time(mov, batch_size=ops['batch_size'])
+    sdmov = standard_deviation_over_time(mov, batch_size=ops["batch_size"])
     mov /= sdmov
-    mov = np.reshape(mov, (-1,Lyc*Lxc))
+    mov = np.reshape(mov, (-1, Lyc * Lxc))
     # compute covariance of binned frames
     cov = mov @ mov.transpose() / mov.shape[1]
-    cov = cov.astype('float32')
+    cov = cov.astype("float32")
 
-    nsvd_for_roi = min(ops['nbinned'], int(cov.shape[0]/2))
+    nsvd_for_roi = min(ops["nbinned"], int(cov.shape[0] / 2))
     u, s, v = np.linalg.svd(cov)
 
     u = u[:, :nsvd_for_roi]
     U = u.transpose() @ mov
-    U = np.reshape(U, (-1,Lyc,Lxc))
+    U = np.reshape(U, (-1, Lyc, Lxc))
     U = np.transpose(U, (1, 2, 0)).copy()
     return ops, U, sdmov, u
 
+
 def getSVDproj(mov: np.ndarray, ops, u):
 
-    mov = temporal_high_pass_filter(mov, int(ops['high_pass']))
+    mov = temporal_high_pass_filter(mov, int(ops["high_pass"]))
 
     nbins, Lyc, Lxc = np.shape(mov)
-    if ('smooth_masks' in ops) and ops['smooth_masks']:
-        sig = np.maximum([.5, .5], ops['diameter']/20.)
+    if ("smooth_masks" in ops) and ops["smooth_masks"]:
+        sig = np.maximum([.5, .5], ops["diameter"] / 20.)
         for j in range(nbins):
-            mov[j,:,:] = gaussian_filter(mov[j,:,:], sig)
+            mov[j, :, :] = gaussian_filter(mov[j, :, :], sig)
     if 1:
-        sdmov = standard_deviation_over_time(mov, batch_size=ops['batch_size'])
-        mov/=sdmov
-        mov = np.reshape(mov, (-1,Lyc*Lxc))
+        sdmov = standard_deviation_over_time(mov, batch_size=ops["batch_size"])
+        mov /= sdmov
+        mov = np.reshape(mov, (-1, Lyc * Lxc))
 
         U = u.transpose() @ mov
-        U = U.transpose().copy().reshape((Lyc,Lxc,-1))
+        U = U.transpose().copy().reshape((Lyc, Lxc, -1))
     else:
         U = np.transpose(mov, (1, 2, 0)).copy()
     return U, sdmov
@@ -61,32 +63,33 @@ def getStU(ops, U):
     Lyc, Lxc, nbins = np.shape(U)
     S = create_neuropil_basis(ops, Lyc, Lxc)
     # compute covariance of neuropil masks with spatial masks
-    StU = S.reshape((Lyc*Lxc,-1)).transpose() @ U.reshape((Lyc*Lxc,-1))
-    StS = S.reshape((Lyc*Lxc,-1)).transpose() @ S.reshape((Lyc*Lxc,-1))
+    StU = S.reshape((Lyc * Lxc, -1)).transpose() @ U.reshape((Lyc * Lxc, -1))
+    StS = S.reshape((Lyc * Lxc, -1)).transpose() @ S.reshape((Lyc * Lxc, -1))
     #U = np.reshape(U, (-1,Lyc,Lxc))
-    return S, StU , StS
+    return S, StU, StS
+
 
 def drawClusters(stat, ops):
-    Ly = ops['Lyc']
-    Lx = ops['Lxc']
+    Ly = ops["Lyc"]
+    Lx = ops["Lxc"]
 
     ncells = len(stat)
-    r=np.random.random((ncells,))
-    iclust = -1*np.ones((Ly,Lx),np.int32)
-    Lam = np.zeros((Ly,Lx))
-    H = np.zeros((Ly,Lx,1))
+    r = np.random.random((ncells,))
+    iclust = -1 * np.ones((Ly, Lx), np.int32)
+    Lam = np.zeros((Ly, Lx))
+    H = np.zeros((Ly, Lx, 1))
     for n in range(ncells):
-        isingle = Lam[stat[n]['ypix'],stat[n]['xpix']]+1e-4 < stat[n]['lam']
-        y = stat[n]['ypix'][isingle]
-        x = stat[n]['xpix'][isingle]
-        Lam[y,x] = stat[n]['lam'][isingle]
+        isingle = Lam[stat[n]["ypix"], stat[n]["xpix"]] + 1e-4 < stat[n]["lam"]
+        y = stat[n]["ypix"][isingle]
+        x = stat[n]["xpix"][isingle]
+        Lam[y, x] = stat[n]["lam"][isingle]
         #iclust[ypix,xpix] = n*np.ones(ypix.shape)
-        H[y,x,0] = r[n]*np.ones(y.shape)
+        H[y, x, 0] = r[n] * np.ones(y.shape)
 
-    S  = np.ones((Ly,Lx,1))
-    V  = np.maximum(0, np.minimum(1, 0.75 * Lam / Lam[Lam>1e-10].mean()))
-    V  = np.expand_dims(V,axis=2)
-    hsv = np.concatenate((H,S,V),axis=2)
+    S = np.ones((Ly, Lx, 1))
+    V = np.maximum(0, np.minimum(1, 0.75 * Lam / Lam[Lam > 1e-10].mean()))
+    V = np.expand_dims(V, axis=2)
+    hsv = np.concatenate((H, S, V), axis=2)
     rgb = hsv_to_rgb(hsv)
 
     return rgb
@@ -109,52 +112,55 @@ def create_neuropil_basis(ops, Ly, Lx):
         basis functions (pixels x nbasis functions)
     """
 
-    if 'ratio_neuropil' in ops:
-        ratio_neuropil = ops['ratio_neuropil']
+    if "ratio_neuropil" in ops:
+        ratio_neuropil = ops["ratio_neuropil"]
     else:
         ratio_neuropil = 6.
-    if 'tile_factor' in ops:
-        tile_factor    = ops['tile_factor']
+    if "tile_factor" in ops:
+        tile_factor = ops["tile_factor"]
     else:
         tile_factor = 1.
-    diameter       = ops['diameter']
-
-    ntilesY  = 1+2*int(np.ceil(tile_factor * Ly / (ratio_neuropil * diameter[0]/2))/2)
-    ntilesX  = 1+2*int(np.ceil(tile_factor * Lx / (ratio_neuropil * diameter[1]/2))/2)
-    ntilesY  = np.maximum(2,ntilesY)
-    ntilesX  = np.maximum(2,ntilesX)
+    diameter = ops["diameter"]
+
+    ntilesY = 1 + 2 * int(
+        np.ceil(tile_factor * Ly / (ratio_neuropil * diameter[0] / 2)) / 2)
+    ntilesX = 1 + 2 * int(
+        np.ceil(tile_factor * Lx / (ratio_neuropil * diameter[1] / 2)) / 2)
+    ntilesY = np.maximum(2, ntilesY)
+    ntilesX = np.maximum(2, ntilesX)
     yc = np.linspace(1, Ly, ntilesY)
     xc = np.linspace(1, Lx, ntilesX)
-    ys = np.arange(0,Ly)
-    xs = np.arange(0,Lx)
+    ys = np.arange(0, Ly)
+    xs = np.arange(0, Lx)
 
-    Kx = np.ones((Lx, ntilesX), 'float32')
-    Ky = np.ones((Ly, ntilesY), 'float32')
+    Kx = np.ones((Lx, ntilesX), "float32")
+    Ky = np.ones((Ly, ntilesY), "float32")
     if 1:
         # basis functions are fourier modes
-        for k in range(int((ntilesX-1)/2)):
-            Kx[:,2*k+1] = np.sin(2*math.pi * (xs+0.5) *  (1+k)/Lx)
-            Kx[:,2*k+2] = np.cos(2*math.pi * (xs+0.5) *  (1+k)/Lx)
-        for k in range(int((ntilesY-1)/2)):
-            Ky[:,2*k+1] = np.sin(2*math.pi * (ys+0.5) *  (1+k)/Ly)
-            Ky[:,2*k+2] = np.cos(2*math.pi * (ys+0.5) *  (1+k)/Ly)
+        for k in range(int((ntilesX - 1) / 2)):
+            Kx[:, 2 * k + 1] = np.sin(2 * math.pi * (xs + 0.5) * (1 + k) / Lx)
+            Kx[:, 2 * k + 2] = np.cos(2 * math.pi * (xs + 0.5) * (1 + k) / Lx)
+        for k in range(int((ntilesY - 1) / 2)):
+            Ky[:, 2 * k + 1] = np.sin(2 * math.pi * (ys + 0.5) * (1 + k) / Ly)
+            Ky[:, 2 * k + 2] = np.cos(2 * math.pi * (ys + 0.5) * (1 + k) / Ly)
     else:
         for k in range(ntilesX):
-            Kx[:,k] = np.cos(math.pi * (xs+0.5) *  k/Lx)
+            Kx[:, k] = np.cos(math.pi * (xs + 0.5) * k / Lx)
         for k in range(ntilesY):
-            Ky[:,k] = np.cos(math.pi * (ys+0.5) *  k/Ly)
+            Ky[:, k] = np.cos(math.pi * (ys + 0.5) * k / Ly)
 
     S = np.zeros((ntilesY, ntilesX, Ly, Lx), np.float32)
     for kx in range(ntilesX):
         for ky in range(ntilesY):
-            S[ky,kx,:,:] = np.outer(Ky[:,ky], Kx[:,kx])
+            S[ky, kx, :, :] = np.outer(Ky[:, ky], Kx[:, kx])
 
-    S = np.reshape(S,(ntilesY*ntilesX, Ly*Lx))
-    S = S / np.reshape(np.sum(S**2,axis=-1)**0.5, (-1,1))
+    S = np.reshape(S, (ntilesY * ntilesX, Ly * Lx))
+    S = S / np.reshape(np.sum(S**2, axis=-1)**0.5, (-1, 1))
     S = np.transpose(S, (1, 0)).copy()
     S = np.reshape(S, (Ly, Lx, -1))
     return S
 
+
 def circleMask(d0):
     """
     creates array with indices which are the radius of that x,y point
@@ -173,21 +179,23 @@ def circleMask(d0):
     dy:
         indices in rs where the radius is less than d0
     """
-    dx = np.tile(np.arange(-d0[1],d0[1]+1)/d0[1], (2*d0[0]+1,1))
-    dy = np.tile(np.arange(-d0[0],d0[0]+1)/d0[0], (2*d0[1]+1,1))
+    dx = np.tile(np.arange(-d0[1], d0[1] + 1) / d0[1], (2 * d0[0] + 1, 1))
+    dy = np.tile(np.arange(-d0[0], d0[0] + 1) / d0[0], (2 * d0[1] + 1, 1))
     dy = dy.transpose()
 
-    rs = (dy**2 + dx**2) ** 0.5
-    dx = dx[rs<=1.]
-    dy = dy[rs<=1.]
+    rs = (dy**2 + dx**2)**0.5
+    dx = dx[rs <= 1.]
+    dy = dy[rs <= 1.]
     return rs, dx, dy
 
+
 def morphOpen(V, footprint):
-    ''' computes the morphological opening of V (correlation map) with circular footprint'''
-    vrem   = filters.minimum_filter(V, footprint=footprint)
-    vrem   = -filters.minimum_filter(-vrem, footprint=footprint)
+    """ computes the morphological opening of V (correlation map) with circular footprint"""
+    vrem = filters.minimum_filter(V, footprint=footprint)
+    vrem = -filters.minimum_filter(-vrem, footprint=footprint)
     return vrem
 
+
 def localMax(V, footprint, thres):
     """
     find local maxima of V (correlation map) using a filter with (usually circular) footprint
@@ -203,37 +211,40 @@ def localMax(V, footprint, thres):
     -------
     i,j: indices of local max greater than thres
     """
-    maxV = filters.maximum_filter(V, footprint=footprint, mode = 'reflect')
+    maxV = filters.maximum_filter(V, footprint=footprint, mode="reflect")
     imax = V > np.maximum(thres, maxV - 1e-10)
-    i,j  = imax.nonzero()
-    i    = i.astype(np.int32)
-    j    = j.astype(np.int32)
-    return i,j
+    i, j = imax.nonzero()
+    i = i.astype(np.int32)
+    j = j.astype(np.int32)
+    return i, j
+
 
-def localRegion(i,j,dy,dx,Ly,Lx):
-    ''' returns valid indices of local region surrounding (i,j) of size (dy.size, dx.size)'''
+def localRegion(i, j, dy, dx, Ly, Lx):
+    """ returns valid indices of local region surrounding (i,j) of size (dy.size, dx.size)"""
     xc = dx + j
     yc = dy + i
-    goodi = (xc>=0) & (xc<Lx) & (yc>=0) & (yc<Ly)
+    goodi = (xc >= 0) & (xc < Lx) & (yc >= 0) & (yc < Ly)
     xc = xc[goodi]
     yc = yc[goodi]
     yc = yc.astype(np.int32)
     xc = xc.astype(np.int32)
     return yc, xc, goodi
 
-def pairwiseDistance(y,x):
-    dists = ((np.expand_dims(y,axis=-1) - np.expand_dims(y,axis=0))**2
-         + (np.expand_dims(x,axis=-1) - np.expand_dims(x,axis=0))**2)**0.5
+
+def pairwiseDistance(y, x):
+    dists = ((np.expand_dims(y, axis=-1) - np.expand_dims(y, axis=0))**2 +
+             (np.expand_dims(x, axis=-1) - np.expand_dims(x, axis=0))**2)**0.5
     return dists
 
 
 def r_squared(yp, xp, ypix, xpix, diam_y, diam_x, estimator=np.median):
-    return np.sqrt(((yp - estimator(ypix)) / diam_y) ** 2 + (((xp - estimator(xpix)) / diam_x) ** 2))
+    return np.sqrt(((yp - estimator(ypix)) / diam_y)**2 +
+                   (((xp - estimator(xpix)) / diam_x)**2))
 
 
 # this function needs to be updated with the new stat
 def get_stat(ops, stats, Ucell, codes, frac=0.5):
-    '''
+    """
     computes statistics of cells found using sourcery
 
     Parameters
@@ -250,53 +261,54 @@ def get_stat(ops, stats, Ucell, codes, frac=0.5):
     -------
     stat
         assigned to stat: ipix, ypix, xpix, med, npix, lam, footprint, compact, aspect_ratio, ellipse
-    '''
-    d0, Ly, Lx = ops['diameter'], ops['Lyc'], ops['Lxc']
+    """
+    d0, Ly, Lx = ops["diameter"], ops["Lyc"], ops["Lxc"]
     rs, dy, dx = circleMask(d0)
     rsort = np.sort(rs.flatten())
 
     # Remove empty cells
-    stats = [stat for stat in stats if len(stat['ypix']) != 0]
+    stats = [stat for stat in stats if len(stat["ypix"]) != 0]
 
     footprints = np.zeros(len(stats))
     for k, (stat, code) in enumerate(zip(stats, codes)):
-        ypix, xpix, lam = stat['ypix'], stat['xpix'], stat['lam']
+        ypix, xpix, lam = stat["ypix"], stat["xpix"], stat["lam"]
 
         # compute footprint of ROI
         yp, xp = extendROI(ypix, xpix, Ly, Lx, int(np.mean(d0)))
 
         # compute compactness of ROI
         rs = r_squared(yp=yp, xp=xp, ypix=ypix, xpix=xpix, diam_y=d0[0], diam_x=d0[1])
-        stat['mrs'] = np.mean(rs)
-        stat['mrs0'] = np.mean(rsort[:ypix.size])
-        stat['compact'] = stat['mrs'] / (1e-10 + stat['mrs0'])
-        stat['med'] = [np.median(stat['ypix']), np.median(stat['xpix'])]
-        stat['npix'] = xpix.size
-        if 'radius' not in stat:
+        stat["mrs"] = np.mean(rs)
+        stat["mrs0"] = np.mean(rsort[:ypix.size])
+        stat["compact"] = stat["mrs"] / (1e-10 + stat["mrs0"])
+        stat["med"] = [np.median(stat["ypix"]), np.median(stat["xpix"])]
+        stat["npix"] = xpix.size
+        if "radius" not in stat:
             ry, rx = fitMVGaus(ypix, xpix, lam, dy=d0[0], dx=d0[1], thres=2).radii
-            stat['radius'] = ry * d0.mean()
-            stat['aspect_ratio'] = 2 * ry/(.01 + ry + rx)
+            stat["radius"] = ry * d0.mean()
+            stat["aspect_ratio"] = 2 * ry / (.01 + ry + rx)
 
         proj = (Ucell[yp, xp, :] @ np.expand_dims(code, axis=1)).flatten()
         footprints[k] = np.nanmean(rs[proj > proj.max() * frac])
 
     mfoot = np.nanmedian(footprints)
     for stat, footprint in zip(stats, footprints):
-        stat['footprint'] = footprint / mfoot if not np.isnan(footprint) else 0
+        stat["footprint"] = footprint / mfoot if not np.isnan(footprint) else 0
 
-    npix = np.array([stat['npix'] for stat in stats], dtype='float32')
+    npix = np.array([stat["npix"] for stat in stats], dtype="float32")
     npix /= np.mean(npix[:100])
     for stat, npix0 in zip(stats, npix):
-        stat['npix_norm'] = npix0
+        stat["npix_norm"] = npix0
 
     return stats
 
 
 def getVmap(Ucell, sig):
-    us = gaussian_filter(Ucell, [sig[0], sig[1], 0.], mode='wrap')
+    us = gaussian_filter(Ucell, [sig[0], sig[1], 0.], mode="wrap")
     # compute log variance at each location
-    log_variances = (us**2).mean(axis=-1) / gaussian_filter((Ucell**2).mean(axis=-1), sig, mode='wrap')
-    return log_variances.astype('float64'), us
+    log_variances = (us**2).mean(axis=-1) / gaussian_filter(
+        (Ucell**2).mean(axis=-1), sig, mode="wrap")
+    return log_variances.astype("float64"), us
 
 
 def sub2ind(array_shape, rows, cols):
@@ -308,223 +320,243 @@ def minDistance(inputs):
     ds = (y1 - np.expand_dims(y2, axis=1))**2 + (x1 - np.expand_dims(x2, axis=1))**2
     return np.amin(ds)**.5
 
+
 def get_connected(Ly, Lx, stat):
-    '''grow i0 until it cannot grow any more
-    '''
-    ypix, xpix, lam = stat['ypix'], stat['xpix'], stat['lam']
-    i0   = np.argmax(lam)
+    """grow i0 until it cannot grow any more
+    """
+    ypix, xpix, lam = stat["ypix"], stat["xpix"], stat["lam"]
+    i0 = np.argmax(lam)
     mask = np.zeros((Ly, Lx))
-    mask[ypix,xpix] = lam
+    mask[ypix, xpix] = lam
     ypix, xpix = ypix[i0], xpix[i0]
     nsel = 1
     while 1:
-        ypix,xpix = extendROI(ypix, xpix, Ly, Lx)
-        ix = mask[ypix,xpix]>1e-10
-        ypix,xpix = ypix[ix], xpix[ix]
-        if len(ypix)<=nsel:
+        ypix, xpix = extendROI(ypix, xpix, Ly, Lx)
+        ix = mask[ypix, xpix] > 1e-10
+        ypix, xpix = ypix[ix], xpix[ix]
+        if len(ypix) <= nsel:
             break
         nsel = len(ypix)
     lam = mask[ypix, xpix]
-    stat['ypix'], stat['xpix'], stat['lam'] = ypix, xpix, lam
+    stat["ypix"], stat["xpix"], stat["lam"] = ypix, xpix, lam
     return stat
 
+
 def connected_region(stat, ops):
-    if ('connected' not in ops) or ops['connected']:
+    if ("connected" not in ops) or ops["connected"]:
         for j in range(len(stat)):
-            stat[j] = get_connected(ops['Lyc'], ops['Lxc'], stat[j])
+            stat[j] = get_connected(ops["Lyc"], ops["Lxc"], stat[j])
     return stat
 
-def extendROI(ypix, xpix, Ly, Lx,niter=1):
+
+def extendROI(ypix, xpix, Ly, Lx, niter=1):
     for k in range(niter):
-        yx = ((ypix, ypix, ypix, ypix-1, ypix+1), (xpix, xpix+1,xpix-1,xpix,xpix))
+        yx = ((ypix, ypix, ypix, ypix - 1, ypix + 1), (xpix, xpix + 1, xpix - 1, xpix,
+                                                       xpix))
         yx = np.array(yx)
-        yx = yx.reshape((2,-1))
+        yx = yx.reshape((2, -1))
         yu = np.unique(yx, axis=1)
-        ix = np.all((yu[0]>=0, yu[0]<Ly, yu[1]>=0 , yu[1]<Lx), axis = 0)
-        ypix,xpix = yu[:, ix]
-    return ypix,xpix
+        ix = np.all((yu[0] >= 0, yu[0] < Ly, yu[1] >= 0, yu[1] < Lx), axis=0)
+        ypix, xpix = yu[:, ix]
+    return ypix, xpix
+
 
 def iter_extend(ypix, xpix, Ucell, code, refine=-1, change_codes=False):
     Lyc, Lxc, nsvd = Ucell.shape
     npix = 0
     iter = 0
-    while npix<10000:
+    while npix < 10000:
         npix = ypix.size
-        ypix, xpix = extendROI(ypix,xpix,Lyc,Lxc, 1)
+        ypix, xpix = extendROI(ypix, xpix, Lyc, Lxc, 1)
         usub = Ucell[ypix, xpix, :]
         lam = usub @ np.expand_dims(code, axis=1)
         lam = np.squeeze(lam, axis=1)
         # ix = lam>max(0, np.mean(lam)/3)
-        ix = lam>max(0, lam.max()/5.0)
-        if ix.sum()==0:
-            break;
-        ypix, xpix,lam = ypix[ix],xpix[ix], lam[ix]
-        lam = lam/np.sum(lam**2+1e-10)**.5
-        if refine<0 and change_codes:
+        ix = lam > max(0, lam.max() / 5.0)
+        if ix.sum() == 0:
+            break
+        ypix, xpix, lam = ypix[ix], xpix[ix], lam[ix]
+        lam = lam / np.sum(lam**2 + 1e-10)**.5
+        if refine < 0 and change_codes:
             code = lam @ usub[ix, :]
         if iter == 0:
             sgn = 1.
             #sgn = np.sign(ix.sum()-npix)
-        if np.sign(sgn * (ix.sum()-npix))<=0:
+        if np.sign(sgn * (ix.sum() - npix)) <= 0:
             break
         else:
             npix = ypix.size
         iter += 1
     return ypix, xpix, lam, ix, code
 
+
 def sourcery(mov: np.ndarray, ops):
     change_codes = True
     i0 = time.time()
-    if isinstance(ops['diameter'], int):
-        ops['diameter'] = [ops['diameter'], ops['diameter']]
-    ops['diameter'] = np.array(ops['diameter'])
-    ops['spatscale_pix'] = ops['diameter'][1]
-    ops['aspect'] = ops['diameter'][0] / ops['diameter'][1]
-    ops, U,sdmov, u   = getSVDdata(mov=mov, ops=ops) # get SVD components
-    S, StU , StS = getStU(ops, U)
-    Lyc, Lxc,nsvd = U.shape
-    ops['Lyc'] = Lyc
-    ops['Lxc'] = Lxc
-    d0 = ops['diameter']
-    sig = np.ceil(d0 / 4) # smoothing constant
+    if isinstance(ops["diameter"], int):
+        ops["diameter"] = [ops["diameter"], ops["diameter"]]
+    ops["diameter"] = np.array(ops["diameter"])
+    ops["spatscale_pix"] = ops["diameter"][1]
+    ops["aspect"] = ops["diameter"][0] / ops["diameter"][1]
+    ops, U, sdmov, u = getSVDdata(mov=mov, ops=ops)  # get SVD components
+    S, StU, StS = getStU(ops, U)
+    Lyc, Lxc, nsvd = U.shape
+    ops["Lyc"] = Lyc
+    ops["Lxc"] = Lxc
+    d0 = ops["diameter"]
+    sig = np.ceil(d0 / 4)  # smoothing constant
     # make array of radii values of size (2*d0+1,2*d0+1)
-    rs,dy,dx     = circleMask(d0)
+    rs, dy, dx = circleMask(d0)
     nsvd = U.shape[-1]
     nbasis = S.shape[-1]
     codes = np.zeros((0, nsvd), np.float32)
     LtU = np.zeros((0, nsvd), np.float32)
     LtS = np.zeros((0, nbasis), np.float32)
-    L   = np.zeros((Lyc, Lxc, 0), np.float32)
+    L = np.zeros((Lyc, Lxc, 0), np.float32)
     # regress maps onto basis functions and subtract neuropil contribution
-    neu   = np.linalg.solve(StS, StU).astype('float32')
-    Ucell = U - (S.reshape((-1,nbasis))@neu).reshape(U.shape)
+    neu = np.linalg.solve(StS, StU).astype("float32")
+    Ucell = U - (S.reshape((-1, nbasis)) @ neu).reshape(U.shape)
 
     it = 0
     ncells = 0
     refine = -1
 
     # initialize
-    ypix,xpix,lam = [], [], []
+    ypix, xpix, lam = [], [], []
 
     while 1:
-        if refine<0:
+        if refine < 0:
             V, us = getVmap(Ucell, sig)
-            if it==0:
-                vrem   = morphOpen(V, rs<=1.)
-            V      = V - vrem # make V more uniform
-            if it==0:
-                V = V.astype('float64')
+            if it == 0:
+                vrem = morphOpen(V, rs <= 1.)
+            V = V - vrem  # make V more uniform
+            if it == 0:
+                V = V.astype("float64")
                 # find indices of all maxima in +/- 1 range
-                maxV   = filters.maximum_filter(V, footprint= np.ones((3,3)), mode='reflect')
-                imax   = V > (maxV - 1e-10)
-                peaks  = V[imax]
+                maxV = filters.maximum_filter(V, footprint=np.ones((3, 3)),
+                                              mode="reflect")
+                imax = V > (maxV - 1e-10)
+                peaks = V[imax]
                 # use the median of these peaks to decide if ROI is accepted
-                thres  = ops['threshold_scaling'] * np.median(peaks[peaks>1e-4])
-                ops['Vcorr'] = V
-            V = np.minimum(V, ops['Vcorr'])
+                thres = ops["threshold_scaling"] * np.median(peaks[peaks > 1e-4])
+                ops["Vcorr"] = V
+            V = np.minimum(V, ops["Vcorr"])
 
             # add extra ROIs here
             n = ncells
-            while n<ncells+200:
+            while n < ncells + 200:
                 ind = np.argmax(V)
-                i,j = np.unravel_index(ind, V.shape)
-                if V[i,j] < thres:
-                    break;
-                yp, xp, la, ix, code = iter_extend(i, j, Ucell, us[i,j,:], change_codes=change_codes)
-                codes = np.append(codes, np.expand_dims(code,axis=0), axis=0)
+                i, j = np.unravel_index(ind, V.shape)
+                if V[i, j] < thres:
+                    break
+                yp, xp, la, ix, code = iter_extend(i, j, Ucell, us[i, j, :],
+                                                   change_codes=change_codes)
+                codes = np.append(codes, np.expand_dims(code, axis=0), axis=0)
                 ypix.append(yp)
                 xpix.append(xp)
                 lam.append(la)
-                Ucell[ypix[n], xpix[n], :] -= np.outer(lam[n], codes[n,:])
+                Ucell[ypix[n], xpix[n], :] -= np.outer(lam[n], codes[n, :])
 
-                yp, xp = extendROI(yp,xp,Lyc,Lxc, int(np.mean(d0)))
+                yp, xp = extendROI(yp, xp, Lyc, Lxc, int(np.mean(d0)))
                 V[yp, xp] = 0
                 n += 1
             newcells = len(ypix) - ncells
-            if it==0:
+            if it == 0:
                 Nfirst = newcells
-            L   = np.append(L, np.zeros((Lyc, Lxc, newcells), 'float32'), axis =-1)
-            LtU = np.append(LtU, np.zeros((newcells, nsvd), 'float32'), axis = 0)
-            LtS = np.append(LtS, np.zeros((newcells, nbasis), 'float32'), axis = 0)
+            L = np.append(L, np.zeros((Lyc, Lxc, newcells), "float32"), axis=-1)
+            LtU = np.append(LtU, np.zeros((newcells, nsvd), "float32"), axis=0)
+            LtS = np.append(LtS, np.zeros((newcells, nbasis), "float32"), axis=0)
             for n in range(ncells, len(ypix)):
-                L[ypix[n],xpix[n], n] = lam[n]
-                LtU[n,:] = lam[n] @ U[ypix[n],xpix[n],:]
-                LtS[n,:] = lam[n] @ S[ypix[n],xpix[n], :]
-            ncells +=newcells
+                L[ypix[n], xpix[n], n] = lam[n]
+                LtU[n, :] = lam[n] @ U[ypix[n], xpix[n], :]
+                LtS[n, :] = lam[n] @ S[ypix[n], xpix[n], :]
+            ncells += newcells
 
             # regression with neuropil
             LtL = L.reshape((-1, ncells)).transpose() @ L.reshape((-1, ncells))
-            cellcode = np.concatenate((LtL,LtS), axis=1)
-            neucode  = np.concatenate((LtS.transpose(),StS), axis=1)
+            cellcode = np.concatenate((LtL, LtS), axis=1)
+            neucode = np.concatenate((LtS.transpose(), StS), axis=1)
             codes = np.concatenate((cellcode, neucode), axis=0)
-            Ucode = np.concatenate((LtU, StU),axis=0)
-            codes = np.linalg.solve(codes + 1e-3*np.eye((codes.shape[0])), Ucode).astype('float32')
-            neu   = codes[ncells:,:]
-            codes = codes[:ncells,:]
-
-        Ucell = U - (S.reshape((-1,nbasis))@neu + L.reshape((-1,ncells))@codes).reshape(U.shape)
+            Ucode = np.concatenate((LtU, StU), axis=0)
+            codes = np.linalg.solve(codes + 1e-3 * np.eye((codes.shape[0])),
+                                    Ucode).astype("float32")
+            neu = codes[ncells:, :]
+            codes = codes[:ncells, :]
+
+        Ucell = U - (S.reshape((-1, nbasis)) @ neu + L.reshape(
+            (-1, ncells)) @ codes).reshape(U.shape)
         # reestimate masks
-        n,k = 0,0
+        n, k = 0, 0
         while n < len(ypix):
-            Ucell[ypix[n], xpix[n], :] += np.outer(lam[n], codes[k,:])
-            ypix[n], xpix[n], lam[n], ix, codes[n,:] = iter_extend(ypix[n], xpix[n], Ucell,
-                codes[k,:], refine, change_codes=change_codes)
-            k+=1
-            if ix.sum()==0:
-                print('dropped ROI with no pixels')
+            Ucell[ypix[n], xpix[n], :] += np.outer(lam[n], codes[k, :])
+            ypix[n], xpix[n], lam[n], ix, codes[n, :] = iter_extend(
+                ypix[n], xpix[n], Ucell, codes[k, :], refine, change_codes=change_codes)
+            k += 1
+            if ix.sum() == 0:
+                print("dropped ROI with no pixels")
                 del ypix[n], xpix[n], lam[n]
-                continue;
-            Ucell[ypix[n], xpix[n], :] -= np.outer(lam[n], codes[n,:])
-            n+=1
+                continue
+            Ucell[ypix[n], xpix[n], :] -= np.outer(lam[n], codes[n, :])
+            n += 1
         codes = codes[:n, :]
         ncells = len(ypix)
-        L   = np.zeros((Lyc,Lxc, ncells), 'float32')
-        LtU = np.zeros((ncells, nsvd),   'float32')
-        LtS = np.zeros((ncells, nbasis), 'float32')
+        L = np.zeros((Lyc, Lxc, ncells), "float32")
+        LtU = np.zeros((ncells, nsvd), "float32")
+        LtS = np.zeros((ncells, nbasis), "float32")
         for n in range(ncells):
-            L[ypix[n],xpix[n],n] = lam[n]
-            if refine<0:
-                LtU[n,:] = lam[n] @ U[ypix[n],xpix[n],:]
-                LtS[n,:] = lam[n] @ S[ypix[n],xpix[n],:]
+            L[ypix[n], xpix[n], n] = lam[n]
+            if refine < 0:
+                LtU[n, :] = lam[n] @ U[ypix[n], xpix[n], :]
+                LtS[n, :] = lam[n] @ S[ypix[n], xpix[n], :]
         err = (Ucell**2).mean()
-        print('ROIs: %d, cost: %2.4f, time: %2.4f'%(ncells, err, time.time()-i0))
+        print("ROIs: %d, cost: %2.4f, time: %2.4f" % (ncells, err, time.time() - i0))
 
         it += 1
-        if refine ==0:
+        if refine == 0:
             break
-        if refine==2:
+        if refine == 2:
             # good place to get connected regions
-            stat = [{'ypix':ypix[n], 'lam':lam[n], 'xpix':xpix[n]} for n in range(ncells)]
+            stat = [{
+                "ypix": ypix[n],
+                "lam": lam[n],
+                "xpix": xpix[n]
+            } for n in range(ncells)]
             stat = connected_region(stat, ops)
             # good place to remove ROIs that overlap, change ncells, codes, ypix, xpix, lam, L
             #stat, ix = remove_overlaps(stat, ops, Lyc, Lxc)
-            #print('removed %d overlapping ROIs'%(len(ypix)-len(ix)))
-            ypix = [stat[n]['ypix'] for n in range(len(stat))]
-            xpix = [stat[n]['xpix'] for n in range(len(stat))]
-            lam = [stat[n]['lam'] for n in range(len(stat))]
+            #print("removed %d overlapping ROIs"%(len(ypix)-len(ix)))
+            ypix = [stat[n]["ypix"] for n in range(len(stat))]
+            xpix = [stat[n]["xpix"] for n in range(len(stat))]
+            lam = [stat[n]["lam"] for n in range(len(stat))]
             #L = L[:,:,ix]
             #codes = codes[ix, :]
             ncells = len(ypix)
-        if refine>0:
-            Ucell = Ucell + (S.reshape((-1,nbasis))@neu).reshape(U.shape)
-        if refine<0 and (newcells<Nfirst/10 or it==ops['max_iterations']):
+        if refine > 0:
+            Ucell = Ucell + (S.reshape((-1, nbasis)) @ neu).reshape(U.shape)
+        if refine < 0 and (newcells < Nfirst / 10 or it == ops["max_iterations"]):
             refine = 3
             U, sdmov = getSVDproj(mov, ops, u)
             Ucell = U
-        if refine>=0:
-            StU = S.reshape((Lyc*Lxc,-1)).transpose() @ Ucell.reshape((Lyc*Lxc,-1))
+        if refine >= 0:
+            StU = S.reshape((Lyc * Lxc, -1)).transpose() @ Ucell.reshape(
+                (Lyc * Lxc, -1))
             #StU = np.reshape(S, (Lyc*Lxc,-1)).transpose() @ np.reshape(Ucell, (Lyc*Lxc, -1))
-            neu = np.linalg.solve(StS, StU).astype('float32')
+            neu = np.linalg.solve(StS, StU).astype("float32")
         refine -= 1
-    Ucell = U - (S.reshape((-1,nbasis))@neu).reshape(U.shape)
+    Ucell = U - (S.reshape((-1, nbasis)) @ neu).reshape(U.shape)
 
     sdmov = np.reshape(sdmov, (Lyc, Lxc))
-    ops['sdmov'] = sdmov
-    stat  = [{'ypix':ypix[n], 'lam':lam[n]*sdmov[ypix[n], xpix[n]], 'xpix':xpix[n]} for n in range(ncells)]
+    ops["sdmov"] = sdmov
+    stat = [{
+        "ypix": ypix[n],
+        "lam": lam[n] * sdmov[ypix[n], xpix[n]],
+        "xpix": xpix[n]
+    } for n in range(ncells)]
 
     stat = postprocess(ops, stat, Ucell, codes)
     return ops, stat
 
+
 def postprocess(ops, stat, Ucell, codes):
     # this is a good place to merge ROIs
     #mPix, mLam, codes = mergeROIs(ops, Lyc,Lxc,d0,mPix,mLam,codes,Ucell)
diff --git a/suite2p/detection/sparsedetect.py b/suite2p/detection/sparsedetect.py
index c5063e9f9..3cab6df23 100644
--- a/suite2p/detection/sparsedetect.py
+++ b/suite2p/detection/sparsedetect.py
@@ -12,42 +12,48 @@
 
 from . import utils
 
+
 def neuropil_subtraction(mov: np.ndarray, filter_size: int) -> None:
     """Returns movie subtracted by a low-pass filtered version of itself to help ignore neuropil."""
     nbinned, Ly, Lx = mov.shape
-    c1 = uniform_filter(np.ones((Ly, Lx)), size=filter_size, mode='constant')
+    c1 = uniform_filter(np.ones((Ly, Lx)), size=filter_size, mode="constant")
     movt = np.zeros_like(mov)
     for frame, framet in zip(mov, movt):
-        framet[:] = frame - (uniform_filter(frame, size=filter_size, mode='constant') / c1)
+        framet[:] = frame - (uniform_filter(frame, size=filter_size, mode="constant") /
+                             c1)
     return movt
 
 
 def square_convolution_2d(mov: np.ndarray, filter_size: int) -> np.ndarray:
-    """Returns movie convolved by uniform kernel with width 'filter_size'."""
+    """Returns movie convolved by uniform kernel with width "filter_size"."""
     movt = np.zeros_like(mov, dtype=np.float32)
     for frame, framet in zip(mov, movt):
-        framet[:] = filter_size * uniform_filter(frame, size=filter_size, mode='constant')
+        framet[:] = filter_size * uniform_filter(frame, size=filter_size,
+                                                 mode="constant")
     return movt
 
 
-def multiscale_mask(ypix0,xpix0,lam0, Lyp, Lxp):
+def multiscale_mask(ypix0, xpix0, lam0, Lyp, Lxp):
     # given a set of masks on the raw image, this functions returns the downsampled masks for all spatial scales
     xs = [xpix0]
     ys = [ypix0]
     lms = [lam0]
-    for j in range(1,len(Lyp)):
-        ipix, ind = np.unique(np.int32(xs[j-1]/2)+np.int32(ys[j-1]/2)*Lxp[j], return_inverse=True)
+    for j in range(1, len(Lyp)):
+        ipix, ind = np.unique(
+            np.int32(xs[j - 1] / 2) + np.int32(ys[j - 1] / 2) * Lxp[j],
+            return_inverse=True)
         LAM = np.zeros(len(ipix))
-        for i in range(len(xs[j-1])):
-            LAM[ind[i]] += lms[j-1][i]/2
+        for i in range(len(xs[j - 1])):
+            LAM[ind[i]] += lms[j - 1][i] / 2
         lms.append(LAM)
-        ys.append(np.int32(ipix/Lxp[j]))
-        xs.append(np.int32(ipix%Lxp[j]))
+        ys.append(np.int32(ipix / Lxp[j]))
+        xs.append(np.int32(ipix % Lxp[j]))
     for j in range(len(Lyp)):
         ys[j], xs[j], lms[j] = extend_mask(ys[j], xs[j], lms[j], Lyp[j], Lxp[j])
     return ys, xs, lms
 
-def add_square(yi,xi,lx,Ly,Lx):
+
+def add_square(yi, xi, lx, Ly, Lx):
     """ return square of pixels around peak with norm 1
     
     Parameters
@@ -81,7 +87,7 @@ def add_square(yi,xi,lx,Ly,Lx):
         pixel weightings
 
     """
-    lhf = int((lx-1)/2)
+    lhf = int((lx - 1) / 2)
     ipix = np.tile(np.arange(-lhf, -lhf + lx, dtype=np.int32), reps=(lx, 1))
     x0 = xi + ipix
     y0 = yi + ipix.T
@@ -125,40 +131,42 @@ def iter_extend(ypix, xpix, mov, Lyc, Lxc, active_frames):
     """
     npix = 0
     iter = 0
-    while npix<10000:
+    while npix < 10000:
         npix = ypix.size
         # extend ROI by 1 pixel on each side
         ypix, xpix = extendROI(ypix, xpix, Lyc, Lxc, 1)
         # activity in proposed ROI on ACTIVE frames
-        usub = mov[np.ix_(active_frames, ypix*Lxc+ xpix)]
-        lam = np.mean(usub,axis=0)
-        ix = lam>max(0, lam.max()/5.0)
-        if ix.sum()==0:
+        usub = mov[np.ix_(active_frames, ypix * Lxc + xpix)]
+        lam = np.mean(usub, axis=0)
+        ix = lam > max(0, lam.max() / 5.0)
+        if ix.sum() == 0:
             break
-        ypix, xpix,lam = ypix[ix],xpix[ix], lam[ix]
+        ypix, xpix, lam = ypix[ix], xpix[ix], lam[ix]
         if iter == 0:
             sgn = 1.
-        if np.sign(sgn * (ix.sum()-npix))<=0:
+        if np.sign(sgn * (ix.sum() - npix)) <= 0:
             break
         else:
             npix = ypix.size
         iter += 1
-    lam = lam/np.sum(lam**2)**.5
+    lam = lam / np.sum(lam**2)**.5
     return ypix, xpix, lam
 
-def extendROI(ypix, xpix, Ly, Lx,niter=1):
+
+def extendROI(ypix, xpix, Ly, Lx, niter=1):
     """ extend ypix and xpix by niter pixel(s) on each side """
     for k in range(niter):
-        yx = ((ypix, ypix, ypix, ypix-1, ypix+1), (xpix, xpix+1,xpix-1,xpix,xpix))
+        yx = ((ypix, ypix, ypix, ypix - 1, ypix + 1), (xpix, xpix + 1, xpix - 1, xpix,
+                                                       xpix))
         yx = np.array(yx)
-        yx = yx.reshape((2,-1))
+        yx = yx.reshape((2, -1))
         yu = np.unique(yx, axis=1)
-        ix = np.all((yu[0]>=0, yu[0]<Ly, yu[1]>=0 , yu[1]<Lx), axis = 0)
-        ypix,xpix = yu[:, ix]
-    return ypix,xpix
+        ix = np.all((yu[0] >= 0, yu[0] < Ly, yu[1] >= 0, yu[1] < Lx), axis=0)
+        ypix, xpix = yu[:, ix]
+    return ypix, xpix
 
 
-def two_comps(mpix0,  lam, Th2):
+def two_comps(mpix0, lam, Th2):
     """ check if splitting ROI increases variance explained
 
     Parameters
@@ -186,12 +194,12 @@ def two_comps(mpix0,  lam, Th2):
     """
     mpix = mpix0.copy()
     xproj = mpix @ lam
-    gf0 = xproj>Th2
+    gf0 = xproj > Th2
 
-    mpix[gf0, :] -= np.outer(xproj[gf0] , lam)
+    mpix[gf0, :] -= np.outer(xproj[gf0], lam)
     vexp0 = np.sum(mpix0**2) - np.sum(mpix**2)
 
-    k = np.argmax(np.sum(mpix * np.float32(mpix>0), axis=1))
+    k = np.argmax(np.sum(mpix * np.float32(mpix > 0), axis=1))
     mu = [lam * np.float32(mpix[k] < 0), lam * np.float32(mpix[k] > 0)]
 
     mpix = mpix0.copy()
@@ -210,43 +218,47 @@ def two_comps(mpix0,  lam, Th2):
         for k in range(2):
             if flag[k]:
                 continue
-            mpix[goodframe[k],:] += np.outer(xproj[k], mu[k])
+            mpix[goodframe[k], :] += np.outer(xproj[k], mu[k])
             xp = mpix @ mu[k]
-            goodframe[k]  = xp > Th2
+            goodframe[k] = xp > Th2
             V[k] = np.sum(xp**2)
-            if np.sum(goodframe[k])==0:
+            if np.sum(goodframe[k]) == 0:
                 flag[k] = True
                 V[k] = -1
                 continue
             xproj[k] = xp[goodframe[k]]
-            mu[k] = np.mean(mpix[goodframe[k], :] * xproj[k][:,np.newaxis], axis=0)
-            mu[k][mu[k]<0]  = 0
-            mu[k] /=(1e-6 + np.sum(mu[k]**2)**.5)
-            mpix[goodframe[k],:] -= np.outer(xproj[k], mu[k])
+            mu[k] = np.mean(mpix[goodframe[k], :] * xproj[k][:, np.newaxis], axis=0)
+            mu[k][mu[k] < 0] = 0
+            mu[k] /= (1e-6 + np.sum(mu[k]**2)**.5)
+            mpix[goodframe[k], :] -= np.outer(xproj[k], mu[k])
     k = np.argmax(V)
     vexp = np.sum(mpix0**2) - np.sum(mpix**2)
     vrat = vexp / vexp0
     return vrat, (mu[k], xproj[k], goodframe[k])
 
+
 def extend_mask(ypix, xpix, lam, Ly, Lx):
     """ extend mask into 8 surrrounding pixels """
     nel = len(xpix)
-    yx = ((ypix, ypix, ypix, ypix-1, ypix-1,ypix-1, ypix+1,ypix+1,ypix+1),
-          (xpix, xpix+1,xpix-1,xpix, xpix+1,xpix-1,xpix, xpix+1,xpix-1))
+    yx = ((ypix, ypix, ypix, ypix - 1, ypix - 1, ypix - 1, ypix + 1, ypix + 1,
+           ypix + 1), (xpix, xpix + 1, xpix - 1, xpix, xpix + 1, xpix - 1, xpix,
+                       xpix + 1, xpix - 1))
     yx = np.array(yx)
-    yx = yx.reshape((2,-1))
+    yx = yx.reshape((2, -1))
     yu, ind = np.unique(yx, axis=1, return_inverse=True)
     LAM = np.zeros(yu.shape[1])
     for j in range(len(ind)):
-        LAM[ind[j]] += lam[j%nel]/3
-    ix = np.all((yu[0]>=0, yu[0]<Ly, yu[1]>=0 , yu[1]<Lx), axis = 0)
-    ypix1,xpix1 = yu[:, ix]
+        LAM[ind[j]] += lam[j % nel] / 3
+    ix = np.all((yu[0] >= 0, yu[0] < Ly, yu[1] >= 0, yu[1] < Lx), axis=0)
+    ypix1, xpix1 = yu[:, ix]
     lam1 = LAM[ix]
-    return ypix1,xpix1,lam1
+    return ypix1, xpix1, lam1
+
 
 class EstimateMode(Enum):
-    Forced = 'FORCED'
-    Estimated = 'estimated'
+    Forced = "FORCED"
+    Estimated = "estimated"
+
 
 def estimate_spatial_scale(I: np.ndarray) -> int:
     I0 = I.max(axis=0)
@@ -256,6 +268,7 @@ def estimate_spatial_scale(I: np.ndarray) -> int:
     im, _ = mode(imap[ipk][isort[:50]], keepdims=True)
     return im
 
+
 def find_best_scale(I: np.ndarray, spatial_scale: int) -> Tuple[int, EstimateMode]:
     """
     Returns best scale and estimate method (if the spatial scale was forced (if positive) or estimated (the top peaks).
@@ -267,27 +280,33 @@ def find_best_scale(I: np.ndarray, spatial_scale: int) -> Tuple[int, EstimateMod
         if scale > 0:
             return scale, EstimateMode.Estimated
         else:
-            warn("Spatial scale estimation failed.  Setting spatial scale to 1 in order to continue.")
+            warn(
+                "Spatial scale estimation failed.  Setting spatial scale to 1 in order to continue."
+            )
             return 1, EstimateMode.Forced
 
-def sparsery(mov: np.ndarray, high_pass: int, neuropil_high_pass: int, batch_size: int, spatial_scale: int, threshold_scaling,
-             max_iterations: int, percentile=0) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
-    """Returns stats and ops from 'mov' using correlations in time."""
+
+def sparsery(mov: np.ndarray, high_pass: int, neuropil_high_pass: int, batch_size: int,
+             spatial_scale: int, threshold_scaling, max_iterations: int,
+             percentile=0) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
+    """Returns stats and ops from "mov" using correlations in time."""
 
     mean_img = mov.mean(axis=0)
     mov = utils.temporal_high_pass_filter(mov=mov, width=int(high_pass))
     max_proj = mov.max(axis=0)
     sdmov = utils.standard_deviation_over_time(mov, batch_size=batch_size)
-    mov = neuropil_subtraction(mov=mov / sdmov, filter_size=neuropil_high_pass)  # subtract low-pass filtered movie
+    mov = neuropil_subtraction(
+        mov=mov / sdmov,
+        filter_size=neuropil_high_pass)  # subtract low-pass filtered movie
 
     _, Lyc, Lxc = mov.shape
     LL = np.meshgrid(np.arange(Lxc), np.arange(Lyc))
-    gxy = [np.array(LL).astype('float32')]
+    gxy = [np.array(LL).astype("float32")]
     dmov = mov
     movu = []
 
     # downsample movie at various spatial scales
-    Lyp, Lxp = np.zeros(5, 'int32'), np.zeros(5, 'int32')  # downsampled sizes
+    Lyp, Lxp = np.zeros(5, "int32"), np.zeros(5, "int32")  # downsampled sizes
     for j in range(5):
         movu0 = square_convolution_2d(dmov, 3)
         dmov = 2 * utils.downsample(dmov)
@@ -300,7 +319,8 @@ def sparsery(mov: np.ndarray, high_pass: int, neuropil_high_pass: int, batch_siz
     I = np.zeros((len(gxy), gxy[0].shape[1], gxy[0].shape[2]))
     for movu0, gxy0, I0 in zip(movu, gxy, I):
         gmodel = RectBivariateSpline(gxy0[1, :, 0], gxy0[0, 0, :], movu0.max(axis=0),
-                                     kx=min(3, gxy0.shape[1] - 1), ky=min(3, gxy0.shape[2] - 1))
+                                     kx=min(3, gxy0.shape[1] - 1),
+                                     ky=min(3, gxy0.shape[2] - 1))
         I0[:] = gmodel(gxy[0][1, :, 0], gxy[0][0, 0, :])
     v_corr = I.max(axis=0)
 
@@ -310,11 +330,13 @@ def sparsery(mov: np.ndarray, high_pass: int, neuropil_high_pass: int, batch_siz
     #    scale = np.argmin(np.abs(scales - diam))
     #    estimate_mode = EstimateMode.Estimated
 
-    spatscale_pix = 3 * 2 ** scale
-    mask_window = int(((spatscale_pix * 1.5)//2)*2)
-    Th2 = threshold_scaling * 5 * max(1, scale)  # threshold for accepted peaks (scale it by spatial scale)
+    spatscale_pix = 3 * 2**scale
+    mask_window = int(((spatscale_pix * 1.5) // 2) * 2)
+    Th2 = threshold_scaling * 5 * max(
+        1, scale)  # threshold for accepted peaks (scale it by spatial scale)
     vmultiplier = max(1, mov.shape[0] / 1200)
-    print('NOTE: %s spatial scale ~%d pixels, time epochs %2.2f, threshold %2.2f ' % (estimate_mode.value, spatscale_pix, vmultiplier, vmultiplier * Th2))
+    print("NOTE: %s spatial scale ~%d pixels, time epochs %2.2f, threshold %2.2f " %
+          (estimate_mode.value, spatscale_pix, vmultiplier, vmultiplier * Th2))
 
     # get standard deviation for pixels for all values > Th2
     v_map = [utils.threshold_reduce(movu0, Th2) for movu0 in movu]
@@ -333,19 +355,19 @@ def sparsery(mov: np.ndarray, high_pass: int, neuropil_high_pass: int, batch_siz
     seeds = []
     extract_patches = False
     for tj in range(max_iterations):
-        # find peaks in stddev's
+        # find peaks in stddev"s
         v0max = np.array([V1[j].max() for j in range(5)])
         imap = np.argmax(v0max)
         imax = np.argmax(V1[imap])
         yi, xi = np.unravel_index(imax, (Lyp[imap], Lxp[imap]))
         # position of peak
-        yi, xi = gxy[imap][1,yi,xi], gxy[imap][0,yi,xi]
+        yi, xi = gxy[imap][1, yi, xi], gxy[imap][0, yi, xi]
         med = [int(yi), int(xi)]
 
         # check if peak is larger than threshold * max(1,nbinned/1200)
         v_max[tj] = v0max.max()
-        if v_max[tj] < vmultiplier*Th2:
-            break   
+        if v_max[tj] < vmultiplier * Th2:
+            break
         ls = lxs[imap]
 
         ihop[tj] = imap
@@ -353,15 +375,15 @@ def sparsery(mov: np.ndarray, high_pass: int, neuropil_high_pass: int, batch_siz
         # make square of initial pixels based on spatial scale of peak
         yi, xi = int(yi), int(xi)
         ypix0, xpix0, lam0 = add_square(yi, xi, ls, Lyc, Lxc)
-        
+
         # project movie into square to get time series
-        tproj = (mov[:, ypix0*Lxc + xpix0] * lam0[0]).sum(axis=-1)
+        tproj = (mov[:, ypix0 * Lxc + xpix0] * lam0[0]).sum(axis=-1)
         if percentile > 0:
             threshold = min(Th2, np.percentile(tproj, percentile))
         else:
             threshold = Th2
-        active_frames = np.nonzero(tproj>threshold)[0] # frames with activity > Th2
-        
+        active_frames = np.nonzero(tproj > threshold)[0]  # frames with activity > Th2
+
         # get square around seed
         if extract_patches:
             mask = mov[active_frames].mean(axis=0).reshape(Lyc, Lxc)
@@ -371,14 +393,14 @@ def sparsery(mov: np.ndarray, high_pass: int, neuropil_high_pass: int, batch_siz
         # extend mask based on activity similarity
         for j in range(3):
             ypix0, xpix0, lam0 = iter_extend(ypix0, xpix0, mov, Lyc, Lxc, active_frames)
-            tproj = mov[:, ypix0*Lxc+ xpix0] @ lam0
-            active_frames = np.nonzero(tproj>threshold)[0]
-            if len(active_frames)<1:
+            tproj = mov[:, ypix0 * Lxc + xpix0] @ lam0
+            active_frames = np.nonzero(tproj > threshold)[0]
+            if len(active_frames) < 1:
                 if tj < nmasks:
                     continue
                 else:
                     break
-        if len(active_frames)<1:
+        if len(active_frames) < 1:
             if tj < nmasks:
                 continue
             else:
@@ -395,38 +417,41 @@ def sparsery(mov: np.ndarray, high_pass: int, neuropil_high_pass: int, batch_siz
             lam0 = lam0[ix]
             ymed = np.median(ypix0)
             xmed = np.median(xpix0)
-            imin = np.argmin((xpix0-xmed)**2 + (ypix0-ymed)**2)
+            imin = np.argmin((xpix0 - xmed)**2 + (ypix0 - ymed)**2)
             med = [ypix0[imin], xpix0[imin]]
-            
+
         # update residual on raw movie
-        mov[np.ix_(active_frames, ypix0*Lxc+ xpix0)] -= tproj[active_frames][:,np.newaxis] * lam0
+        mov[np.ix_(active_frames,
+                   ypix0 * Lxc + xpix0)] -= tproj[active_frames][:, np.newaxis] * lam0
         # update filtered movie
-        ys, xs, lms = multiscale_mask(ypix0,xpix0,lam0, Lyp, Lxp)
+        ys, xs, lms = multiscale_mask(ypix0, xpix0, lam0, Lyp, Lxp)
         for j in range(nscales):
-            movu[j][np.ix_(active_frames, xs[j]+Lxp[j]*ys[j])] -= np.outer(tproj[active_frames], lms[j])
-            Mx = movu[j][:,xs[j]+Lxp[j]*ys[j]]
-            V1[j][ys[j], xs[j]] = (Mx**2 * np.float32(Mx>threshold)).sum(axis=0)**.5
+            movu[j][np.ix_(active_frames, xs[j] + Lxp[j] * ys[j])] -= np.outer(
+                tproj[active_frames], lms[j])
+            Mx = movu[j][:, xs[j] + Lxp[j] * ys[j]]
+            V1[j][ys[j], xs[j]] = (Mx**2 * np.float32(Mx > threshold)).sum(axis=0)**.5
 
         stats.append({
-            'ypix': ypix0.astype(int),
-            'xpix': xpix0.astype(int),
-            'lam': lam0 * sdmov[ypix0, xpix0],
-            'med': med,
-            'footprint': ihop[tj]
+            "ypix": ypix0.astype(int),
+            "xpix": xpix0.astype(int),
+            "lam": lam0 * sdmov[ypix0, xpix0],
+            "med": med,
+            "footprint": ihop[tj]
         })
-        
+
         if tj % 1000 == 0:
-            print('%d ROIs, score=%2.2f' % (tj, v_max[tj]))
+            print("%d ROIs, score=%2.2f" % (tj, v_max[tj]))
 
-        
     new_ops = {
-        'max_proj': max_proj,
-        'Vmax': v_max,
-        'ihop': ihop,
-        'Vsplit': v_split,
-        'Vcorr': v_corr,
-        'Vmap': np.asanyarray(v_map, dtype='object'), # needed so that scipy.io.savemat doesn't fail in runpipeline with latest numpy (v1.24.3). dtype='object' is needed to have numpy array with elements having diff sizes
-        'spatscale_pix': spatscale_pix,
+        "max_proj": max_proj,
+        "Vmax": v_max,
+        "ihop": ihop,
+        "Vsplit": v_split,
+        "Vcorr": v_corr,
+        "Vmap": np.asanyarray(
+            v_map, dtype="object"
+        ),  # needed so that scipy.io.savemat doesn"t fail in runpipeline with latest numpy (v1.24.3). dtype="object" is needed to have numpy array with elements having diff sizes
+        "spatscale_pix": spatscale_pix,
     }
 
-    return new_ops, stats
\ No newline at end of file
+    return new_ops, stats
diff --git a/suite2p/detection/stats.py b/suite2p/detection/stats.py
index 140349d45..73752e569 100644
--- a/suite2p/detection/stats.py
+++ b/suite2p/detection/stats.py
@@ -10,18 +10,20 @@
 
 
 def distance_kernel(radius: int) -> np.ndarray:
-    """ Returns 2D array containing geometric distance from center, with radius 'radius'"""
+    """ Returns 2D array containing geometric distance from center, with radius "radius" """
     d = np.arange(-radius, radius + 1)
     dists_2d = norm(np.meshgrid(d, d), axis=0)
     return dists_2d
 
+
 def median_pix(ypix, xpix):
     ymed, xmed = np.median(ypix), np.median(xpix)
-    imin = np.argmin((xpix-xmed)**2 + (ypix-ymed)**2)
+    imin = np.argmin((xpix - xmed)**2 + (ypix - ymed)**2)
     xmed = xpix[imin]
     ymed = ypix[imin]
     return [ymed, xmed]
 
+
 class EllipseData(NamedTuple):
     mu: float
     cov: float
@@ -32,7 +34,7 @@ class EllipseData(NamedTuple):
 
     @property
     def area(self):
-        return (self.radii[0] * self.radii[1]) ** 0.5 * np.pi
+        return (self.radii[0] * self.radii[1])**0.5 * np.pi
 
     @property
     def radius(self) -> float:
@@ -51,7 +53,8 @@ class ROI:
     lam: np.ndarray
     med: np.ndarray
     do_crop: bool
-    rsort: np.ndarray = field(default=np.sort(distance_kernel(radius=30).flatten()), repr=False)
+    rsort: np.ndarray = field(default=np.sort(distance_kernel(radius=30).flatten()),
+                              repr=False)
 
     def __post_init__(self):
         """Validate inputs."""
@@ -60,7 +63,8 @@ def __post_init__(self):
 
     @classmethod
     def from_stat_dict(cls, stat: Dict[str, Any], do_crop: bool = True) -> ROI:
-        return cls(ypix=stat['ypix'], xpix=stat['xpix'], lam=stat['lam'], med=stat['med'], do_crop=do_crop)
+        return cls(ypix=stat["ypix"], xpix=stat["xpix"], lam=stat["lam"],
+                   med=stat["med"], do_crop=do_crop)
 
     def to_array(self, Ly: int, Lx: int) -> np.ndarray:
         """Returns a 2D boolean array of shape (Ly x Lx) indicating where the roi is located."""
@@ -69,14 +73,15 @@ def to_array(self, Ly: int, Lx: int) -> np.ndarray:
         return arr
 
     @classmethod
-    def stats_dicts_to_3d_array(cls, stats: Sequence[Dict[str, Any]], Ly: int, Lx: int, label_id: bool = False):
+    def stats_dicts_to_3d_array(cls, stats: Sequence[Dict[str, Any]], Ly: int, Lx: int,
+                                label_id: bool = False):
         """
         Outputs a (roi x Ly x Lx) float array from a sequence of stat dicts.
         Convenience function that repeatedly calls ROI.from_stat_dict() and ROI.to_array() for all rois.
 
         Parameters
         ----------
-        stats : List of dictionary 'ypix', 'xpix', 'lam'
+        stats : List of dictionary "ypix", "xpix", "lam"
         Ly : y size of frame
         Lx : x size of frame
         label_id : whether array should be an integer value indicating ROI id or just 1 (indicating precence of ROI).
@@ -94,11 +99,14 @@ def ravel_indices(self, Ly: int, Lx: int) -> np.ndarray:
         return np.ravel_multi_index((self.ypix, self.xpix), (Ly, Lx))
 
     @classmethod
-    def get_overlap_count_image(cls, rois: Sequence[ROI], Ly: int, Lx: int) -> np.ndarray:
-        return count_overlaps(Ly=Ly, Lx=Lx, ypixs=[roi.ypix for roi in rois], xpixs=[roi.xpix for roi in rois])
+    def get_overlap_count_image(cls, rois: Sequence[ROI], Ly: int,
+                                Lx: int) -> np.ndarray:
+        return count_overlaps(Ly=Ly, Lx=Lx, ypixs=[roi.ypix for roi in rois],
+                              xpixs=[roi.xpix for roi in rois])
 
     @classmethod
-    def filter_overlappers(cls, rois: Sequence[ROI], overlap_image: np.ndarray, max_overlap: float) -> List[bool]:
+    def filter_overlappers(cls, rois: Sequence[ROI], overlap_image: np.ndarray,
+                           max_overlap: float) -> List[bool]:
         """returns logical array of rois that remain after removing those that overlap more than fraction max_overlap from overlap_img."""
         return filter_overlappers(
             ypixs=[roi.ypix for roi in rois],
@@ -110,7 +118,7 @@ def filter_overlappers(cls, rois: Sequence[ROI], overlap_image: np.ndarray, max_
     def get_overlap_image(self, overlap_count_image: np.ndarray) -> np.ndarray:
         return overlap_count_image[self.ypix, self.xpix] > 1
 
-    @property 
+    @property
     def soma_crop(self) -> np.ndarray:
         if self.do_crop and self.ypix.size > 10:
             dists = ((self.ypix - self.med[0])**2 + (self.xpix - self.med[1])**2)**0.5
@@ -126,11 +134,11 @@ def soma_crop(self) -> np.ndarray:
                 if len(np.nonzero(darea[ida:] < threshold)[0]):
                     radius = radii[np.nonzero(darea[ida:] < threshold)[0][0] + ida]
             crop = dists < radius
-            if crop.sum()==0:
-                crop = np.ones(self.ypix.size, 'bool')
+            if crop.sum() == 0:
+                crop = np.ones(self.ypix.size, "bool")
             return crop
         else:
-            return np.ones(self.ypix.size, 'bool')
+            return np.ones(self.ypix.size, "bool")
 
     @property
     def mean_r_squared(self) -> float:
@@ -149,8 +157,8 @@ def mean_r_squared_compact(self) -> float:
     @property
     def solidity(self) -> float:
         if self.npix_soma > 10:
-            points = np.stack((self.ypix[self.soma_crop], 
-                               self.xpix[self.soma_crop]), axis=1)
+            points = np.stack((self.ypix[self.soma_crop], self.xpix[self.soma_crop]),
+                              axis=1)
             try:
                 hull = ConvexHull(points)
                 volume = hull.volume
@@ -161,10 +169,12 @@ def solidity(self) -> float:
         return self.npix_soma / volume
 
     @classmethod
-    def get_mean_r_squared_normed_all(cls, rois: Sequence[ROI], first_n: int = 100) -> np.ndarray:
-        return norm_by_average([roi.mean_r_squared for roi in rois], estimator=np.nanmedian, offset=1e-10, first_n=first_n)
+    def get_mean_r_squared_normed_all(cls, rois: Sequence[ROI],
+                                      first_n: int = 100) -> np.ndarray:
+        return norm_by_average([roi.mean_r_squared for roi in rois],
+                               estimator=np.nanmedian, offset=1e-10, first_n=first_n)
 
-    @property 
+    @property
     def npix_soma(self) -> int:
         return self.soma_crop.sum()
 
@@ -173,14 +183,13 @@ def n_pixels(self) -> int:
         return self.xpix.size
 
     @classmethod
-    def get_n_pixels_normed_all(cls, rois: Sequence[ROI], first_n: int = 100) -> np.ndarray:
+    def get_n_pixels_normed_all(cls, rois: Sequence[ROI],
+                                first_n: int = 100) -> np.ndarray:
         return norm_by_average([roi.n_pixels for roi in rois], first_n=first_n)
 
     def fit_ellipse(self, dy: float, dx: float) -> EllipseData:
-        return fitMVGaus(self.ypix[self.soma_crop], 
-                         self.xpix[self.soma_crop], 
-                         self.lam[self.soma_crop], 
-                         dy=dy, dx=dx, thres=2)
+        return fitMVGaus(self.ypix[self.soma_crop], self.xpix[self.soma_crop],
+                         self.lam[self.soma_crop], dy=dy, dx=dx, thres=2)
 
 
 def roi_stats(stat, Ly: int, Lx: int, aspect=None, diameter=None, max_overlap=None,
@@ -190,7 +199,7 @@ def roi_stats(stat, Ly: int, Lx: int, aspect=None, diameter=None, max_overlap=No
     Parameters
     ----------
     stat : dictionary
-        'ypix', 'xpix', 'lam'
+        "ypix", "xpix", "lam"
     
     FOV size : (Ly, Lx)
 
@@ -201,60 +210,67 @@ def roi_stats(stat, Ly: int, Lx: int, aspect=None, diameter=None, max_overlap=No
     Returns
     -------
     stat : dictionary
-        adds 'npix', 'npix_norm', 'med', 'footprint', 'compact', 'radius', 'aspect_ratio'
+        adds "npix", "npix_norm", "med", "footprint", "compact", "radius", "aspect_ratio"
     """
-    if 'med' not in stat[0]:
+    if "med" not in stat[0]:
         for s in stat:
-            s['med'] = median_pix(s['ypix'], s['xpix'])
+            s["med"] = median_pix(s["ypix"], s["xpix"])
 
     # approx size of masks for ROI aspect ratio estimation
-    d0 = 10 if diameter is None or (isinstance(diameter, int) and diameter==0) else diameter
+    d0 = 10 if diameter is None or (isinstance(diameter, int) and
+                                    diameter == 0) else diameter
     if aspect is not None:
         diameter = int(d0[0]) if isinstance(d0, (list, np.ndarray)) else int(d0)
         dy, dx = int(aspect * diameter), diameter
     else:
-        dy, dx = (int(d0), int(d0)) if not isinstance(d0, (list, np.ndarray)) else (int(d0[0]), int(d0[0]))
-        
-    rois = [ROI(ypix=s['ypix'], xpix=s['xpix'], 
-                lam=s['lam'], med=s['med'], do_crop=do_crop) for s in stat]
+        dy, dx = (int(d0),
+                  int(d0)) if not isinstance(d0, (list, np.ndarray)) else (int(d0[0]),
+                                                                           int(d0[0]))
+
+    rois = [
+        ROI(ypix=s["ypix"], xpix=s["xpix"], lam=s["lam"], med=s["med"], do_crop=do_crop)
+        for s in stat
+    ]
     n_overlaps = ROI.get_overlap_count_image(rois=rois, Ly=Ly, Lx=Lx)
     for roi, s in zip(rois, stat):
-        s['mrs'] = roi.mean_r_squared
-        s['mrs0'] = roi.mean_r_squared0
-        s['compact'] = roi.mean_r_squared_compact
-        s['solidity'] = roi.solidity
-        s['npix'] = roi.n_pixels
-        s['npix_soma'] = roi.npix_soma
-        s['soma_crop'] = roi.soma_crop
-        s['overlap'] = roi.get_overlap_image(n_overlaps)
+        s["mrs"] = roi.mean_r_squared
+        s["mrs0"] = roi.mean_r_squared0
+        s["compact"] = roi.mean_r_squared_compact
+        s["solidity"] = roi.solidity
+        s["npix"] = roi.n_pixels
+        s["npix_soma"] = roi.npix_soma
+        s["soma_crop"] = roi.soma_crop
+        s["overlap"] = roi.get_overlap_image(n_overlaps)
         ellipse = roi.fit_ellipse(dy, dx)
-        s['radius'] = ellipse.radius
-        s['aspect_ratio'] = ellipse.aspect_ratio
-
-    mrs_normeds = norm_by_average(
-        values=np.array([s['mrs'] for s in stat]), estimator=np.nanmedian, offset=1e-10, first_n=100
-    )
-    npix_normeds = norm_by_average(
-        values=np.array([s['npix'] for s in stat]), first_n=100
-    )
-    npix_soma_normeds = norm_by_average(
-        values=np.array([s['npix_soma'] for s in stat]), first_n=100
-    )
-    for s, mrs_normed, npix_normed, npix_soma_normed in zip(stat, mrs_normeds, npix_normeds, npix_soma_normeds):
-        s['mrs'] = mrs_normed
-        s['npix_norm_no_crop'] = npix_normed
-        s['npix_norm'] = npix_soma_normed
-        s['footprint'] = 0 if 'footprint' not in s else s['footprint']
-
-    if  max_overlap is not None and max_overlap<1.0:
-        keep_rois = ROI.filter_overlappers(rois=rois, overlap_image=n_overlaps, max_overlap=max_overlap)
+        s["radius"] = ellipse.radius
+        s["aspect_ratio"] = ellipse.aspect_ratio
+
+    mrs_normeds = norm_by_average(values=np.array([s["mrs"] for s in stat]),
+                                  estimator=np.nanmedian, offset=1e-10, first_n=100)
+    npix_normeds = norm_by_average(values=np.array([s["npix"] for s in stat]),
+                                   first_n=100)
+    npix_soma_normeds = norm_by_average(values=np.array([s["npix_soma"] for s in stat]),
+                                        first_n=100)
+    for s, mrs_normed, npix_normed, npix_soma_normed in zip(stat, mrs_normeds,
+                                                            npix_normeds,
+                                                            npix_soma_normeds):
+        s["mrs"] = mrs_normed
+        s["npix_norm_no_crop"] = npix_normed
+        s["npix_norm"] = npix_soma_normed
+        s["footprint"] = 0 if "footprint" not in s else s["footprint"]
+
+    if max_overlap is not None and max_overlap < 1.0:
+        keep_rois = ROI.filter_overlappers(rois=rois, overlap_image=n_overlaps,
+                                           max_overlap=max_overlap)
         stat = stat[keep_rois]
         n_overlaps = ROI.get_overlap_count_image(rois=rois, Ly=Ly, Lx=Lx)
-        rois = [ROI(ypix=s['ypix'], xpix=s['xpix'], 
-                lam=s['lam'], med=s['med'], do_crop=do_crop) for s in stat]
+        rois = [
+            ROI(ypix=s["ypix"], xpix=s["xpix"], lam=s["lam"], med=s["med"],
+                do_crop=do_crop) for s in stat
+        ]
         for roi, s in zip(rois, stat):
-            s['overlap'] = roi.get_overlap_image(n_overlaps)
-        
+            s["overlap"] = roi.get_overlap_image(n_overlaps)
+
     return stat
 
 
@@ -282,19 +298,19 @@ def fitMVGaus(y, x, lam0, dy, dx, thres=2.5, npts: int = 100) -> EllipseData:
 
     # normalize pixel weights
     lam = lam0.copy()
-    ix = lam > 0#lam.max()/5
+    ix = lam > 0  #lam.max()/5
     y, x, lam = y[ix], x[ix], lam[ix]
     lam /= lam.sum()
 
     # mean of gaussian
     yx = np.stack((y, x))
     mu = (lam * yx).sum(axis=1)
-    yx = (yx - mu[:, np.newaxis]) * lam ** .5
+    yx = (yx - mu[:, np.newaxis]) * lam**.5
     cov = yx @ yx.T
 
     # radii of major and minor axes
     radii, evec = np.linalg.eig(cov)
-    radii = thres * np.maximum(0, np.real(radii)) ** .5
+    radii = thres * np.maximum(0, np.real(radii))**.5
 
     # compute pts of ellipse
     theta = np.linspace(0, 2 * np.pi, npts)
@@ -303,23 +319,30 @@ def fitMVGaus(y, x, lam0, dy, dx, thres=2.5, npts: int = 100) -> EllipseData:
     radii = np.sort(radii)[::-1]
     return EllipseData(mu=mu, cov=cov, radii=radii, ellipse=ellipse, dy=dy, dx=dx)
 
+
 def count_overlaps(Ly: int, Lx: int, ypixs, xpixs) -> np.ndarray:
     overlap = np.zeros((Ly, Lx))
     for xpix, ypix in zip(xpixs, ypixs):
         overlap[ypix, xpix] += 1
     return overlap
 
-def filter_overlappers(ypixs, xpixs, overlap_image: np.ndarray, max_overlap: float) -> List[bool]:
+
+def filter_overlappers(ypixs, xpixs, overlap_image: np.ndarray,
+                       max_overlap: float) -> List[bool]:
     """returns ROI indices that remain after removing those that overlap more than fraction max_overlap from overlap_img."""
     n_overlaps = overlap_image.copy()
     keep_rois = []
-    for ypix, xpix in reversed(list(zip(ypixs, xpixs))):  # todo: is there an ordering effect here that affects which rois will be removed and which will stay?
+    for ypix, xpix in reversed(
+            list(zip(ypixs, xpixs))
+    ):  # todo: is there an ordering effect here that affects which rois will be removed and which will stay?
         keep_roi = np.mean(n_overlaps[ypix, xpix] > 1) <= max_overlap
         keep_rois.append(keep_roi)
         if not keep_roi:
             n_overlaps[ypix, xpix] -= 1
     return keep_rois[::-1]
 
-def norm_by_average(values: np.ndarray, estimator=np.mean, first_n: int = 100, offset: float = 0.) -> np.ndarray:
-    """Returns array divided by the (average of the 'first_n' values + offset), calculating the average with 'estimator'."""
-    return np.array(values, dtype='float32') / (estimator(values[:first_n]) + offset)
+
+def norm_by_average(values: np.ndarray, estimator=np.mean, first_n: int = 100,
+                    offset: float = 0.) -> np.ndarray:
+    """Returns array divided by the (average of the "first_n" values + offset), calculating the average with "estimator"."""
+    return np.array(values, dtype="float32") / (estimator(values[:first_n]) + offset)
diff --git a/suite2p/detection/utils.py b/suite2p/detection/utils.py
index 3a08c7ac3..4a8f30bb3 100644
--- a/suite2p/detection/utils.py
+++ b/suite2p/detection/utils.py
@@ -3,30 +3,34 @@
 from scipy.optimize import linear_sum_assignment
 from scipy.ndimage import gaussian_filter
 
+
 def square_mask(mask, ly, yi, xi):
     """ crop from mask a square of size ly at position yi,xi """
     Lyc, Lxc = mask.shape
-    mask0 = np.zeros((2*ly, 2*ly), mask.dtype)
-    yinds = [max(0, yi-ly), min(yi+ly, Lyc)]
-    xinds = [max(0, xi-ly), min(xi+ly, Lxc)]        
-    mask0[max(0, ly-yi) : min(2*ly, Lyc+ly-yi), 
-          max(0, ly-xi) : min(2*ly, Lxc+ly-xi)] = mask[yinds[0]:yinds[1], xinds[0]:xinds[1]]
+    mask0 = np.zeros((2 * ly, 2 * ly), mask.dtype)
+    yinds = [max(0, yi - ly), min(yi + ly, Lyc)]
+    xinds = [max(0, xi - ly), min(xi + ly, Lxc)]
+    mask0[max(0, ly - yi):min(2 * ly, Lyc + ly - yi),
+          max(0, ly - xi):min(2 * ly, Lxc + ly - xi)] = mask[yinds[0]:yinds[1],
+                                                             xinds[0]:xinds[1]]
     return mask0
 
+
 def mask_stats(mask):
     """ median and diameter of mask """
-    y,x = np.nonzero(mask)
+    y, x = np.nonzero(mask)
     y = y.astype(np.int32)
     x = x.astype(np.int32)
     ymed = np.median(y)
     xmed = np.median(x)
-    imin = np.argmin((x-xmed)**2 + (y-ymed)**2)
+    imin = np.argmin((x - xmed)**2 + (y - ymed)**2)
     xmed = x[imin]
     ymed = y[imin]
     diam = len(y)**0.5
-    diam /= (np.pi**0.5)/2
+    diam /= (np.pi**0.5) / 2
     return ymed, xmed, diam
 
+
 def mask_ious(masks_true, masks_pred):
     """ return best-matched masks 
     
@@ -49,20 +53,21 @@ def mask_ious(masks_true, masks_pred):
         full IOU matrix across all pairs
 
     """
-    iou = _intersection_over_union(masks_true, masks_pred)[1:,1:]
+    iou = _intersection_over_union(masks_true, masks_pred)[1:, 1:]
     iout, preds = match_masks(iou)
     return iout, preds, iou
 
+
 def match_masks(iou):
     n_min = min(iou.shape[0], iou.shape[1])
-    costs = -(iou >= 0.5).astype(float) - iou / (2*n_min)
+    costs = -(iou >= 0.5).astype(float) - iou / (2 * n_min)
     true_ind, pred_ind = linear_sum_assignment(costs)
     iout = np.zeros(iou.shape[0])
-    iout[true_ind] = iou[true_ind,pred_ind]
-    preds = np.zeros(iou.shape[0], 'int')
-    preds[true_ind] = pred_ind+1
+    iout[true_ind] = iou[true_ind, pred_ind]
+    preds = np.zeros(iou.shape[0], "int")
+    preds[true_ind] = pred_ind + 1
     return iout, preds
-    
+
 
 @jit(nopython=True)
 def _label_overlap(x, y):
@@ -85,11 +90,12 @@ def _label_overlap(x, y):
     """
     x = x.ravel()
     y = y.ravel()
-    overlap = np.zeros((1+x.max(),1+y.max()), dtype=np.uint)
+    overlap = np.zeros((1 + x.max(), 1 + y.max()), dtype=np.uint)
     for i in range(len(x)):
-        overlap[x[i],y[i]] += 1
+        overlap[x[i], y[i]] += 1
     return overlap
 
+
 def _intersection_over_union(masks_true, masks_pred):
     """ intersection over union of all mask pairs
     
@@ -115,9 +121,10 @@ def _intersection_over_union(masks_true, masks_pred):
     iou[np.isnan(iou)] = 0.0
     return iou
 
+
 def hp_gaussian_filter(mov: np.ndarray, width: int) -> np.ndarray:
     """
-    Returns a high-pass-filtered copy of the 3D array 'mov' using a gaussian kernel.
+    Returns a high-pass-filtered copy of the 3D array "mov" using a gaussian kernel.
 
     Parameters
     ----------
@@ -139,7 +146,7 @@ def hp_gaussian_filter(mov: np.ndarray, width: int) -> np.ndarray:
 
 def hp_rolling_mean_filter(mov: np.ndarray, width: int) -> np.ndarray:
     """
-    Returns a high-pass-filtered copy of the 3D array 'mov' using a non-overlapping rolling mean kernel over time.
+    Returns a high-pass-filtered copy of the 3D array "mov" using a non-overlapping rolling mean kernel over time.
 
     Parameters
     ----------
@@ -176,9 +183,10 @@ def temporal_high_pass_filter(mov: np.ndarray, width: int) -> np.ndarray:
     filtered_mov: nImg x Ly x Lx
         The filtered frames
     """
-    
-    return hp_gaussian_filter(mov, width) if width < 10 else hp_rolling_mean_filter(mov, width)  # gaussian is slower
-    
+
+    return hp_gaussian_filter(mov, width) if width < 10 else hp_rolling_mean_filter(
+        mov, width)  # gaussian is slower
+
 
 def standard_deviation_over_time(mov: np.ndarray, batch_size: int) -> np.ndarray:
     """
@@ -198,16 +206,16 @@ def standard_deviation_over_time(mov: np.ndarray, batch_size: int) -> np.ndarray
     """
     nbins, Ly, Lx = mov.shape
     batch_size = min(batch_size, nbins)
-    sdmov = np.zeros((Ly, Lx), 'float32')
+    sdmov = np.zeros((Ly, Lx), "float32")
     for ix in range(0, nbins, batch_size):
-        sdmov += ((np.diff(mov[ix:ix+batch_size, :, :], axis=0) ** 2).sum(axis=0))
+        sdmov += ((np.diff(mov[ix:ix + batch_size, :, :], axis=0)**2).sum(axis=0))
     sdmov = np.maximum(1e-10, np.sqrt(sdmov / nbins))
     return sdmov
 
 
 def downsample(mov: np.ndarray, taper_edge: bool = True) -> np.ndarray:
     """
-    Returns a pixel-downsampled movie from 'mov', tapering the edges of 'taper_edge' is True.
+    Returns a pixel-downsampled movie from "mov", tapering the edges of "taper_edge" is True.
 
     Parameters
     ----------
@@ -224,14 +232,14 @@ def downsample(mov: np.ndarray, taper_edge: bool = True) -> np.ndarray:
     n_frames, Ly, Lx = mov.shape
 
     # bin along Y
-    movd = np.zeros((n_frames, int(np.ceil(Ly / 2)), Lx), 'float32')
-    movd[:, :Ly//2, :] = np.mean([mov[:, 0:-1:2, :], mov[:, 1::2, :]], axis=0)
+    movd = np.zeros((n_frames, int(np.ceil(Ly / 2)), Lx), "float32")
+    movd[:, :Ly // 2, :] = np.mean([mov[:, 0:-1:2, :], mov[:, 1::2, :]], axis=0)
     if Ly % 2 == 1:
         movd[:, -1, :] = mov[:, -1, :] / 2 if taper_edge else mov[:, -1, :]
 
     # bin along X
-    mov2 = np.zeros((n_frames, int(np.ceil(Ly / 2)), int(np.ceil(Lx / 2))), 'float32')
-    mov2[:, :, :Lx//2] = np.mean([movd[:, :, 0:-1:2], movd[:, :, 1::2]], axis=0)
+    mov2 = np.zeros((n_frames, int(np.ceil(Ly / 2)), int(np.ceil(Lx / 2))), "float32")
+    mov2[:, :, :Lx // 2] = np.mean([movd[:, :, 0:-1:2], movd[:, :, 1::2]], axis=0)
     if Lx % 2 == 1:
         mov2[:, :, -1] = movd[:, :, -1] / 2 if taper_edge else movd[:, :, -1]
 
@@ -240,7 +248,7 @@ def downsample(mov: np.ndarray, taper_edge: bool = True) -> np.ndarray:
 
 def threshold_reduce(mov: np.ndarray, intensity_threshold: float) -> np.ndarray:
     """
-    Returns standard deviation of pixels, thresholded by 'intensity_threshold'.
+    Returns standard deviation of pixels, thresholded by "intensity_threshold".
     Run in a loop to reduce memory footprint.
 
     Parameters
@@ -256,9 +264,8 @@ def threshold_reduce(mov: np.ndarray, intensity_threshold: float) -> np.ndarray:
         The standard deviation of the non-thresholded pixels
     """
     nbinned, Lyp, Lxp = mov.shape
-    Vt = np.zeros((Lyp,Lxp), 'float32')
+    Vt = np.zeros((Lyp, Lxp), "float32")
     for t in range(nbinned):
         Vt += mov[t]**2 * (mov[t] > intensity_threshold)
     Vt = Vt**.5
     return Vt
-
diff --git a/suite2p/extraction/dcnv.py b/suite2p/extraction/dcnv.py
index 1cd953115..94348d1f6 100644
--- a/suite2p/extraction/dcnv.py
+++ b/suite2p/extraction/dcnv.py
@@ -3,35 +3,40 @@
 from scipy.ndimage import maximum_filter1d, minimum_filter1d, gaussian_filter
 
 
-@njit(['float32[:], float32[:], float32[:], int64[:], float32[:], float32[:], float32, float32'], cache=True)
+@njit([
+    "float32[:], float32[:], float32[:], int64[:], float32[:], float32[:], float32, float32"
+], cache=True)
 def oasis_trace(F, v, w, t, l, s, tau, fs):
     """ spike deconvolution on a single neuron """
     NT = F.shape[0]
-    g = -1./(tau * fs)
+    g = -1. / (tau * fs)
 
     it = 0
     ip = 0
 
-    while it<NT:
-        v[ip], w[ip],t[ip],l[ip] = F[it],1,it,1
-        while ip>0:
-            if v[ip-1] * np.exp(g * l[ip-1]) > v[ip]:
+    while it < NT:
+        v[ip], w[ip], t[ip], l[ip] = F[it], 1, it, 1
+        while ip > 0:
+            if v[ip - 1] * np.exp(g * l[ip - 1]) > v[ip]:
                 # violation of the constraint means merging pools
-                f1 = np.exp(g * l[ip-1])
-                f2 = np.exp(2 * g * l[ip-1])
-                wnew = w[ip-1] + w[ip] * f2
-                v[ip-1] = (v[ip-1] * w[ip-1] + v[ip] * w[ip]* f1) / wnew
-                w[ip-1] = wnew
-                l[ip-1] = l[ip-1] + l[ip]
+                f1 = np.exp(g * l[ip - 1])
+                f2 = np.exp(2 * g * l[ip - 1])
+                wnew = w[ip - 1] + w[ip] * f2
+                v[ip - 1] = (v[ip - 1] * w[ip - 1] + v[ip] * w[ip] * f1) / wnew
+                w[ip - 1] = wnew
+                l[ip - 1] = l[ip - 1] + l[ip]
                 ip -= 1
             else:
                 break
         it += 1
         ip += 1
 
-    s[t[1:ip]] = v[1:ip] - v[:ip-1] * np.exp(g * l[:ip-1])
+    s[t[1:ip]] = v[1:ip] - v[:ip - 1] * np.exp(g * l[:ip - 1])
 
-@njit(['float32[:,:], float32[:,:], float32[:,:], int64[:,:], float32[:,:], float32[:,:], float32, float32'], parallel=True, cache=True)
+
+@njit([
+    "float32[:,:], float32[:,:], float32[:,:], int64[:,:], float32[:,:], float32[:,:], float32, float32"
+], parallel=True, cache=True)
 def oasis_matrix(F, v, w, t, l, s, tau, fs):
     """ spike deconvolution on many neurons parallelized with prange  """
     for n in prange(F.shape[0]):
@@ -66,26 +71,26 @@ def oasis(F: np.ndarray, batch_size: int, tau: float, fs: float) -> np.ndarray:
         size [neurons x time], deconvolved fluorescence
 
     """
-    NN,NT = F.shape
+    NN, NT = F.shape
     F = F.astype(np.float32)
-    S = np.zeros((NN,NT), dtype=np.float32)
+    S = np.zeros((NN, NT), dtype=np.float32)
     for i in range(0, NN, batch_size):
-        f = F[i:i+batch_size]
-        v = np.zeros((f.shape[0],NT), dtype=np.float32)
-        w = np.zeros((f.shape[0],NT), dtype=np.float32)
-        t = np.zeros((f.shape[0],NT), dtype=np.int64)
-        l = np.zeros((f.shape[0],NT), dtype=np.float32)
-        s = np.zeros((f.shape[0],NT), dtype=np.float32)
+        f = F[i:i + batch_size]
+        v = np.zeros((f.shape[0], NT), dtype=np.float32)
+        w = np.zeros((f.shape[0], NT), dtype=np.float32)
+        t = np.zeros((f.shape[0], NT), dtype=np.int64)
+        l = np.zeros((f.shape[0], NT), dtype=np.float32)
+        s = np.zeros((f.shape[0], NT), dtype=np.float32)
         oasis_matrix(f, v, w, t, l, s, tau, fs)
-        S[i:i+batch_size] = s
+        S[i:i + batch_size] = s
     return S
 
 
-def preprocess(F: np.ndarray, baseline: str, win_baseline: float,
-               sig_baseline: float, fs: float, prctile_baseline: float = 8) -> np.ndarray:
+def preprocess(F: np.ndarray, baseline: str, win_baseline: float, sig_baseline: float,
+               fs: float, prctile_baseline: float = 8) -> np.ndarray:
     """ preprocesses fluorescence traces for spike deconvolution
 
-    baseline-subtraction with window 'win_baseline'
+    baseline-subtraction with window "win_baseline"
     
     Parameters
     ----------------
@@ -115,17 +120,17 @@ def preprocess(F: np.ndarray, baseline: str, win_baseline: float,
         size [neurons x time], baseline-corrected fluorescence
 
     """
-    win = int(win_baseline*fs)
-    if baseline == 'maximin':
-        Flow = gaussian_filter(F,    [0., sig_baseline])
-        Flow = minimum_filter1d(Flow,    win)
-        Flow = maximum_filter1d(Flow,    win)
-    elif baseline == 'constant':
-        Flow = gaussian_filter(F,    [0., sig_baseline])
+    win = int(win_baseline * fs)
+    if baseline == "maximin":
+        Flow = gaussian_filter(F, [0., sig_baseline])
+        Flow = minimum_filter1d(Flow, win)
+        Flow = maximum_filter1d(Flow, win)
+    elif baseline == "constant":
+        Flow = gaussian_filter(F, [0., sig_baseline])
         Flow = np.amin(Flow)
-    elif baseline == 'constant_prctile':
+    elif baseline == "constant_prctile":
         Flow = np.percentile(F, prctile_baseline, axis=1)
-        Flow = np.expand_dims(Flow, axis = 1)
+        Flow = np.expand_dims(Flow, axis=1)
     else:
         Flow = 0.
 
diff --git a/suite2p/extraction/extract.py b/suite2p/extraction/extract.py
index 4c3b114da..c9e726237 100644
--- a/suite2p/extraction/extract.py
+++ b/suite2p/extraction/extract.py
@@ -6,24 +6,25 @@
 from numba.typed import List
 from scipy import stats, signal
 from .masks import create_masks
-from ..io import BinaryRWFile
+from ..io import BinaryFile
 from .. import default_ops
 
+
 def extract_traces(f_in, cell_masks, neuropil_masks, batch_size=500):
     """ extracts activity from f_in using masks in stat and neuropil_masks
     
-    computes fluorescence F as sum of pixels weighted by 'lam'
+    computes fluorescence F as sum of pixels weighted by "lam"
     computes neuropil fluorescence Fneu as sum of pixels in neuropil_masks
 
-    data is from reg_file ops['batch_size'] by pixels:
+    data is from reg_file ops["batch_size"] by pixels:
     .. code-block:: python
-        F[n] = data[:, stat[n]['ipix']] @ stat[n]['lam']
+        F[n] = data[:, stat[n]["ipix"]] @ stat[n]["lam"]
         Fneu = neuropil_masks @ data.T
 
     Parameters
     ----------------
 
-    f_in : np.ndarray or io.BinaryRWFile object
+    f_in : np.ndarray or io.BinaryFile object
         size n_frames, Ly, Lx
 
         
@@ -51,15 +52,15 @@ def extract_traces(f_in, cell_masks, neuropil_masks, batch_size=500):
 
     """
     n_frames, Ly, Lx = f_in.shape
-    t0=time.time()
+    t0 = time.time()
     batch_size = min(batch_size, 1000)
     ncells = len(cell_masks)
-    
-    F    = np.zeros((ncells, n_frames),np.float32)
-    Fneu = np.zeros((ncells, n_frames),np.float32)
+
+    F = np.zeros((ncells, n_frames), np.float32)
+    Fneu = np.zeros((ncells, n_frames), np.float32)
 
     batch_size = int(batch_size)
-    
+
     cell_ipix, cell_lam = List(), List()
     [cell_ipix.append(cell_mask[0].astype(np.int64)) for cell_mask in cell_masks]
     [cell_lam.append(cell_mask[1].astype(np.float32)) for cell_mask in cell_masks]
@@ -69,40 +70,51 @@ def extract_traces(f_in, cell_masks, neuropil_masks, batch_size=500):
 
     if neuropil_masks is not None:
         neuropil_ipix = List()
-        if isinstance(neuropil_masks, np.ndarray) and neuropil_masks.shape[1] == Ly*Lx:
-            [neuropil_ipix.append(np.nonzero(neuropil_mask)[0]) for neuropil_mask in neuropil_masks]
+        if isinstance(neuropil_masks,
+                      np.ndarray) and neuropil_masks.shape[1] == Ly * Lx:
+            [
+                neuropil_ipix.append(np.nonzero(neuropil_mask)[0])
+                for neuropil_mask in neuropil_masks
+            ]
         else:
-            [neuropil_ipix.append(neuropil_mask.astype(np.int64)) for neuropil_mask in neuropil_masks]
-        neuropil_npix = np.array([len(neuropil_ipixi) for neuropil_ipixi in neuropil_ipix]).astype(np.float32)
+            [
+                neuropil_ipix.append(neuropil_mask.astype(np.int64))
+                for neuropil_mask in neuropil_masks
+            ]
+        neuropil_npix = np.array([
+            len(neuropil_ipixi) for neuropil_ipixi in neuropil_ipix
+        ]).astype(np.float32)
     else:
         neuropil_ipix = None
 
     ix = 0
     for k in np.arange(0, n_frames, batch_size):
-        data = f_in[k : min(k + batch_size, n_frames)].astype('float32')
+        data = f_in[k:min(k + batch_size, n_frames)].astype("float32")
         nimg = data.shape[0]
         if nimg == 0:
             break
-        inds = ix+np.arange(0,nimg,1,int)
-        data = np.reshape(data, (nimg,-1)).astype(np.float32)
+        inds = ix + np.arange(0, nimg, 1, int)
+        data = np.reshape(data, (nimg, -1)).astype(np.float32)
         Fi = np.zeros((ncells, data.shape[0]), np.float32)
-        
+
         # extract traces and neuropil
-        
+
         # (WITHOUT NUMBA)
         #for n in range(ncells):
         #    F[n,inds] = np.dot(data[:, cell_masks[n][0]], cell_masks[n][1])
         #Fneu[:,inds] = np.dot(neuropil_masks , data.T)
 
         # WITH NUMBA
-        F[:,inds] = matmul_traces(Fi, data, cell_ipix, cell_lam)
+        F[:, inds] = matmul_traces(Fi, data, cell_ipix, cell_lam)
         if neuropil_ipix is not None:
-            Fneu[:,inds] = matmul_neuropil(Fi, data, neuropil_ipix, neuropil_npix)
+            Fneu[:, inds] = matmul_neuropil(Fi, data, neuropil_ipix, neuropil_npix)
 
         ix += nimg
-    print('Extracted fluorescence from %d ROIs in %d frames, %0.2f sec.'%(ncells, n_frames, time.time()-t0))
+    print("Extracted fluorescence from %d ROIs in %d frames, %0.2f sec." %
+          (ncells, n_frames, time.time() - t0))
     return F, Fneu
 
+
 @njit(parallel=True)
 def matmul_traces(Fi, data, cell_ipix, cell_lam):
     ncells = Fi.shape[0]
@@ -110,6 +122,7 @@ def matmul_traces(Fi, data, cell_ipix, cell_lam):
         Fi[n] = np.dot(data[:, cell_ipix[n]], cell_lam[n])
     return Fi
 
+
 @njit(parallel=True)
 def matmul_neuropil(Fi, data, neuropil_ipix, neuropil_npix):
     ncells = Fi.shape[0]
@@ -124,18 +137,20 @@ def extract_traces_from_masks(ops, cell_masks, neuropil_masks):
     also used in drawroi.py
     
     """
-    batch_size=ops['batch_size']
+    batch_size = ops["batch_size"]
     F_chan2, Fneu_chan2 = [], []
-    with BinaryRWFile(Ly=ops['Ly'], Lx=ops['Lx'],
-                      filename=ops['reg_file']) as f:    
+    with BinaryFile(Ly=ops["Ly"], Lx=ops["Lx"], filename=ops["reg_file"]) as f:
         F, Fneu = extract_traces(f, cell_masks, neuropil_masks, batch_size=batch_size)
-    if 'reg_file_chan2' in ops:
-        with BinaryRWFile(Ly=ops['Ly'], Lx=ops['Lx'],
-                          filename=ops['reg_file_chan2']) as f:    
-            F_chan2, Fneu_chan2 = extract_traces(f, cell_masks, neuropil_masks, batch_size=batch_size)
+    if "reg_file_chan2" in ops:
+        with BinaryFile(Ly=ops["Ly"], Lx=ops["Lx"],
+                        filename=ops["reg_file_chan2"]) as f:
+            F_chan2, Fneu_chan2 = extract_traces(f, cell_masks, neuropil_masks,
+                                                 batch_size=batch_size)
     return F, Fneu, F_chan2, Fneu_chan2
 
-def extraction_wrapper(stat, f_reg, f_reg_chan2=None, cell_masks=None, neuropil_masks=None, ops=default_ops()):
+
+def extraction_wrapper(stat, f_reg, f_reg_chan2=None, cell_masks=None,
+                       neuropil_masks=None, ops=default_ops()):
     """ 
     Main extraction function
     creates masks, computes fluorescence
@@ -145,10 +160,10 @@ def extraction_wrapper(stat, f_reg, f_reg_chan2=None, cell_masks=None, neuropil_
 
     stat : array of dicts
 
-    f_reg : array of functional frames, np.ndarray or io.BinaryRWFile
+    f_reg : array of functional frames, np.ndarray or io.BinaryFile
         n_frames x Ly x Lx
 
-    f_reg_chan2 : array of anatomical frames, np.ndarray or io.BinaryRWFile
+    f_reg_chan2 : array of anatomical frames, np.ndarray or io.BinaryFile
         n_frames x Ly x Lx
 
 
@@ -156,7 +171,7 @@ def extraction_wrapper(stat, f_reg, f_reg_chan2=None, cell_masks=None, neuropil_
     ----------------
 
     stat : list of dictionaries
-        adds keys 'skew' and 'std'
+        adds keys "skew" and "std"
 
     F : fluorescence of functional channel
 
@@ -168,34 +183,36 @@ def extraction_wrapper(stat, f_reg, f_reg_chan2=None, cell_masks=None, neuropil_
 
     """
     n_frames, Ly, Lx = f_reg.shape
-    batch_size=ops['batch_size']
+    batch_size = ops["batch_size"]
     if cell_masks is None:
         t10 = time.time()
         cell_masks, neuropil_masks0 = create_masks(stat, Ly, Lx, ops)
         if neuropil_masks is None:
             neuropil_masks = neuropil_masks0
-        print('Masks created, %0.2f sec.' % (time.time() - t10))    
+        print("Masks created, %0.2f sec." % (time.time() - t10))
 
     F, Fneu = extract_traces(f_reg, cell_masks, neuropil_masks, batch_size=batch_size)
     if f_reg_chan2 is not None:
-        F_chan2, Fneu_chan2 = extract_traces(f_reg_chan2, cell_masks, neuropil_masks, batch_size=batch_size)
+        F_chan2, Fneu_chan2 = extract_traces(f_reg_chan2, cell_masks, neuropil_masks,
+                                             batch_size=batch_size)
     else:
         F_chan2, Fneu_chan2 = [], []
 
     # subtract neuropil
-    dF = F - ops['neucoeff'] * Fneu
+    dF = F - ops["neucoeff"] * Fneu
 
     # compute activity statistics for classifier
     sk = stats.skew(dF, axis=1)
     sd = np.std(dF, axis=1)
     for k in range(F.shape[0]):
-        stat[k]['skew'] = sk[k]
-        stat[k]['std'] = sd[k]
+        stat[k]["skew"] = sk[k]
+        stat[k]["std"] = sd[k]
         if not neuropil_masks is None:
-            stat[k]['neuropil_mask'] = neuropil_masks[k]
-    
+            stat[k]["neuropil_mask"] = neuropil_masks[k]
+
     return stat, F, Fneu, F_chan2, Fneu_chan2
 
+
 def create_masks_and_extract(ops, stat, cell_masks=None, neuropil_masks=None):
     """ creates masks, computes fluorescence, and saves stat, F, and Fneu to .npy
 
@@ -203,9 +220,9 @@ def create_masks_and_extract(ops, stat, cell_masks=None, neuropil_masks=None):
     ----------------
 
     ops : dictionary
-        'Ly', 'Lx', 'reg_file', 'neucoeff', 'ops_path', 
-        'save_path', 'sparse_mode', 'nframes', 'batch_size'
-        (optional 'reg_file_chan2', 'chan2_thres')
+        "Ly", "Lx", "reg_file", "neucoeff", "ops_path", 
+        "save_path", "sparse_mode", "nframes", "batch_size"
+        (optional "reg_file_chan2", "chan2_thres")
 
     stat : array of dicts
 
@@ -213,7 +230,7 @@ def create_masks_and_extract(ops, stat, cell_masks=None, neuropil_masks=None):
     ----------------
 
     stat : list of dictionaries
-        adds keys 'skew' and 'std'
+        adds keys "skew" and "std"
 
     F : fluorescence of functional channel
 
@@ -229,55 +246,54 @@ def create_masks_and_extract(ops, stat, cell_masks=None, neuropil_masks=None):
         raise ValueError("stat array should not be of length 0 (no ROIs were found)")
 
     # create cell and neuropil masks
-    Ly, Lx = ops['Ly'], ops['Lx']
-    reg_file = ops['reg_file']
-    reg_file_alt = ops.get('reg_file_chan2', ops['reg_file'])
-    with BinaryRWFile(Ly=Ly, Lx=Lx, filename=reg_file) as f_in,\
-         BinaryRWFile(Ly=Ly, Lx=Lx, filename=reg_file_alt) as f_in_chan2:         
-        if ops['nchannels'] == 1:
-            f_in_chan2.close() 
+    Ly, Lx = ops["Ly"], ops["Lx"]
+    reg_file = ops["reg_file"]
+    reg_file_alt = ops.get("reg_file_chan2", ops["reg_file"])
+    with BinaryFile(Ly=Ly, Lx=Lx, filename=reg_file) as f_in,\
+         BinaryFile(Ly=Ly, Lx=Lx, filename=reg_file_alt) as f_in_chan2:
+        if ops["nchannels"] == 1:
+            f_in_chan2.close()
             f_in_chan2 = None
-        
-        stat, F, Fneu, F_chan2, Fneu_chan2 = extraction_wrapper(stat, f_in, 
-                                                                f_reg_chan2=f_in_chan2, 
-                                                                cell_masks=cell_masks,
-                                                                neuropil_masks=neuropil_masks,
-                                                                ops=ops)
-    
+
+        stat, F, Fneu, F_chan2, Fneu_chan2 = extraction_wrapper(
+            stat, f_in, f_reg_chan2=f_in_chan2, cell_masks=cell_masks,
+            neuropil_masks=neuropil_masks, ops=ops)
+
     return stat, F, Fneu, F_chan2, Fneu_chan2
-    
+
 
 def enhanced_mean_image(ops):
     """ computes enhanced mean image and adds it to ops
 
-    Median filters ops['meanImg'] with 4*diameter in 2D and subtracts and
+    Median filters ops["meanImg"] with 4*diameter in 2D and subtracts and
     divides by this median-filtered image to return a high-pass filtered
-    image ops['meanImgE']
+    image ops["meanImgE"]
 
     Parameters
     ----------
     ops : dictionary
-        uses 'meanImg', 'aspect', 'spatscale_pix', 'yrange' and 'xrange'
+        uses "meanImg", "aspect", "spatscale_pix", "yrange" and "xrange"
 
     Returns
     -------
         ops : dictionary
-            'meanImgE' field added
+            "meanImgE" field added
 
     """
 
-    I = ops['meanImg'].astype(np.float32)
-    if 'spatscale_pix' not in ops:
-        if isinstance(ops['diameter'], int):
-            diameter = np.array([ops['diameter'], ops['diameter']])
+    I = ops["meanImg"].astype(np.float32)
+    if "spatscale_pix" not in ops:
+        if isinstance(ops["diameter"], int):
+            diameter = np.array([ops["diameter"], ops["diameter"]])
         else:
-            diameter = np.array(ops['diameter'])
-        if diameter[0]==0:
+            diameter = np.array(ops["diameter"])
+        if diameter[0] == 0:
             diameter[:] = 12
-        ops['spatscale_pix'] = diameter[1]
-        ops['aspect'] = diameter[0]/diameter[1]
+        ops["spatscale_pix"] = diameter[1]
+        ops["aspect"] = diameter[0] / diameter[1]
 
-    diameter = 4*np.ceil(np.array([ops['spatscale_pix'] * ops['aspect'], ops['spatscale_pix']])) + 1
+    diameter = 4 * np.ceil(
+        np.array([ops["spatscale_pix"] * ops["aspect"], ops["spatscale_pix"]])) + 1
     diameter = diameter.flatten().astype(np.int64)
     Imed = signal.medfilt2d(I, [diameter[0], diameter[1]])
     I = I - Imed
@@ -287,12 +303,11 @@ def enhanced_mean_image(ops):
     mimg99 = 6
     mimg0 = I
 
-    mimg0 = mimg0[ops['yrange'][0]:ops['yrange'][1], ops['xrange'][0]:ops['xrange'][1]]
+    mimg0 = mimg0[ops["yrange"][0]:ops["yrange"][1], ops["xrange"][0]:ops["xrange"][1]]
     mimg0 = (mimg0 - mimg1) / (mimg99 - mimg1)
-    mimg0 = np.maximum(0,np.minimum(1,mimg0))
-    mimg = mimg0.min() * np.ones((ops['Ly'],ops['Lx']),np.float32)
-    mimg[ops['yrange'][0]:ops['yrange'][1],
-        ops['xrange'][0]:ops['xrange'][1]] = mimg0
-    ops['meanImgE'] = mimg
-    print('added enhanced mean image')
+    mimg0 = np.maximum(0, np.minimum(1, mimg0))
+    mimg = mimg0.min() * np.ones((ops["Ly"], ops["Lx"]), np.float32)
+    mimg[ops["yrange"][0]:ops["yrange"][1], ops["xrange"][0]:ops["xrange"][1]] = mimg0
+    ops["meanImgE"] = mimg
+    print("added enhanced mean image")
     return ops
diff --git a/suite2p/extraction/masks.py b/suite2p/extraction/masks.py
index 10ea1f3a7..6635856ce 100644
--- a/suite2p/extraction/masks.py
+++ b/suite2p/extraction/masks.py
@@ -6,26 +6,29 @@
 from ..detection.sparsedetect import extendROI
 from .. import default_ops
 
+
 def create_masks(stats: List[Dict[str, Any]], Ly, Lx, ops=default_ops()):
     """ create cell and neuropil masks """
 
-    cell_pix = create_cell_pix(stats, Ly=Ly, Lx=Lx, 
-                               lam_percentile=ops.get('lam_percentile', 50.0))
-    cell_masks = [create_cell_mask(stat, Ly=Ly, Lx=Lx, allow_overlap=ops['allow_overlap']) for stat in stats]
-    if ops.get('neuropil_extract', True):
+    cell_pix = create_cell_pix(stats, Ly=Ly, Lx=Lx,
+                               lam_percentile=ops.get("lam_percentile", 50.0))
+    cell_masks = [
+        create_cell_mask(stat, Ly=Ly, Lx=Lx, allow_overlap=ops["allow_overlap"])
+        for stat in stats
+    ]
+    if ops.get("neuropil_extract", True):
         neuropil_masks = create_neuropil_masks(
-            ypixs=[stat['ypix'] for stat in stats],
-            xpixs=[stat['xpix'] for stat in stats],
-            cell_pix=cell_pix,
-            inner_neuropil_radius=ops['inner_neuropil_radius'],
-            min_neuropil_pixels=ops['min_neuropil_pixels'],
-            circular=ops.get('circular_neuropil', False)
-        )
+            ypixs=[stat["ypix"] for stat in stats],
+            xpixs=[stat["xpix"] for stat in stats], cell_pix=cell_pix,
+            inner_neuropil_radius=ops["inner_neuropil_radius"],
+            min_neuropil_pixels=ops["min_neuropil_pixels"],
+            circular=ops.get("circular_neuropil", False))
     else:
         neuropil_masks = None
     return cell_masks, neuropil_masks
 
-def create_cell_pix(stats: List[Dict[str, Any]], Ly: int, Lx: int, 
+
+def create_cell_pix(stats: List[Dict[str, Any]], Ly: int, Lx: int,
                     lam_percentile: float = 50.0) -> np.ndarray:
     """Returns Ly x Lx array of whether pixel contains a cell (1) or not (0).
     
@@ -36,30 +39,32 @@ def create_cell_pix(stats: List[Dict[str, Any]], Ly: int, Lx: int,
     cell_pix = np.zeros((Ly, Lx))
     lammap = np.zeros((Ly, Lx))
     radii = np.zeros(len(stats))
-    for ni,stat in enumerate(stats):
-        radii[ni] = stat['radius']
-        ypix = stat['ypix']
-        xpix = stat['xpix']
-        lam = stat['lam']
+    for ni, stat in enumerate(stats):
+        radii[ni] = stat["radius"]
+        ypix = stat["ypix"]
+        xpix = stat["xpix"]
+        lam = stat["lam"]
         lammap[ypix, xpix] = np.maximum(lammap[ypix, xpix], lam)
     radius = np.median(radii)
     if lam_percentile > 0.0:
-        filt = percentile_filter(lammap, percentile=lam_percentile, size=int(radius*5))
-        cell_pix = ~np.logical_or(lammap < filt, lammap==0)
+        filt = percentile_filter(lammap, percentile=lam_percentile,
+                                 size=int(radius * 5))
+        cell_pix = ~np.logical_or(lammap < filt, lammap == 0)
     else:
         cell_pix = lammap > 0.0
 
     return cell_pix
 
 
-def create_cell_mask(stat: Dict[str, Any], Ly: int, Lx: int, allow_overlap: bool = False) -> Tuple[np.ndarray, np.ndarray]:
+def create_cell_mask(stat: Dict[str, Any], Ly: int, Lx: int,
+                     allow_overlap: bool = False) -> Tuple[np.ndarray, np.ndarray]:
     """
     creates cell masks for ROIs in stat and computes radii
 
     Parameters
     ----------
 
-    stat : dictionary 'ypix', 'xpix', 'lam'
+    stat : dictionary "ypix", "xpix", "lam"
     Ly : y size of frame
     Lx : x size of frame
     allow_overlap : whether or not to include overlapping pixels in cell masks
@@ -70,16 +75,16 @@ def create_cell_mask(stat: Dict[str, Any], Ly: int, Lx: int, allow_overlap: bool
     cell_masks : len ncells, each has tuple of pixels belonging to each cell and weights
     lam_normed
     """
-    mask = ... if allow_overlap else ~stat['overlap']
-    cell_mask = np.ravel_multi_index((stat['ypix'], stat['xpix']), (Ly, Lx))
+    mask = ... if allow_overlap else ~stat["overlap"]
+    cell_mask = np.ravel_multi_index((stat["ypix"], stat["xpix"]), (Ly, Lx))
     cell_mask = cell_mask[mask]
-    lam = stat['lam'][mask]
+    lam = stat["lam"][mask]
     lam_normed = lam / lam.sum() if lam.size > 0 else np.empty(0)
     return cell_mask, lam_normed
 
 
-
-def create_neuropil_masks(ypixs, xpixs, cell_pix, inner_neuropil_radius, min_neuropil_pixels, circular=False):
+def create_neuropil_masks(ypixs, xpixs, cell_pix, inner_neuropil_radius,
+                          min_neuropil_pixels, circular=False):
     """ creates surround neuropil masks for ROIs in stat by EXTENDING ROI (slower if circular)
 
     Parameters
@@ -102,27 +107,36 @@ def create_neuropil_masks(ypixs, xpixs, cell_pix, inner_neuropil_radius, min_neu
     Ly, Lx = cell_pix.shape
     assert len(xpixs) == len(ypixs)
     neuropil_ipix = []
-    idx=0
+    idx = 0
     for ypix, xpix in zip(ypixs, xpixs):
         neuropil_mask = np.zeros((Ly, Lx), bool)
         # extend to get ring of dis-allowed pixels
         ypix, xpix = extendROI(ypix, xpix, Ly, Lx, niter=inner_neuropil_radius)
-        nring = np.sum(valid_pixels(cell_pix, ypix, xpix))  # count how many pixels are valid
+        nring = np.sum(valid_pixels(cell_pix, ypix,
+                                    xpix))  # count how many pixels are valid
 
         nreps = count()
         ypix1, xpix1 = ypix.copy(), xpix.copy()
-        while next(nreps) < 100 and np.sum(valid_pixels(cell_pix, ypix1, xpix1)) - nring <= min_neuropil_pixels:
+        while next(nreps) < 100 and np.sum(valid_pixels(
+                cell_pix, ypix1, xpix1)) - nring <= min_neuropil_pixels:
             if circular:
-                ypix1, xpix1 = extendROI(ypix1, xpix1, Ly, Lx, extend_by)  # keep extending
+                ypix1, xpix1 = extendROI(ypix1, xpix1, Ly, Lx,
+                                         extend_by)  # keep extending
             else:
-                ypix1, xpix1 = np.meshgrid(np.arange(max(0, ypix1.min() - extend_by), min(Ly, ypix1.max() + extend_by + 1), 1, int), 
-                                           np.arange(max(0, xpix1.min() - extend_by), min(Lx, xpix1.max() + extend_by + 1), 1, int),
-                                           indexing='ij')
-            
+                ypix1, xpix1 = np.meshgrid(
+                    np.arange(max(0,
+                                  ypix1.min() - extend_by),
+                              min(Ly,
+                                  ypix1.max() + extend_by + 1), 1, int),
+                    np.arange(max(0,
+                                  xpix1.min() - extend_by),
+                              min(Lx,
+                                  xpix1.max() + extend_by + 1), 1, int), indexing="ij")
+
         ix = valid_pixels(cell_pix, ypix1, xpix1)
         neuropil_mask[ypix1[ix], xpix1[ix]] = True
         neuropil_mask[ypix, xpix] = False
         neuropil_ipix.append(np.ravel_multi_index(np.nonzero(neuropil_mask), (Ly, Lx)))
-        idx+=1
+        idx += 1
 
-    return neuropil_ipix
\ No newline at end of file
+    return neuropil_ipix
diff --git a/suite2p/gui/buttons.py b/suite2p/gui/buttons.py
index 345a58d1b..b99c52668 100644
--- a/suite2p/gui/buttons.py
+++ b/suite2p/gui/buttons.py
@@ -34,6 +34,7 @@ def make_selection(parent):
     parent.topedit.returnPressed.connect(parent.top_number_chosen)
     parent.l0.addWidget(parent.topedit, 0, 11, 1, 1)
 
+
 # minimize view
 def make_cellnotcell(parent):
     """ buttons for cell / not cell views at top """
@@ -59,41 +60,48 @@ def make_cellnotcell(parent):
         b += 1
     parent.sizebtns.setExclusive(True)
 
+
 def make_quadrants(parent):
     """ make quadrant buttons """
     parent.quadbtns = QButtonGroup(parent)
     for b in range(9):
-        btn = QuadButton(b, ' '+str(b+1), parent)
+        btn = QuadButton(b, " " + str(b + 1), parent)
         parent.quadbtns.addButton(btn, b)
-        parent.l0.addWidget(btn, 0 + parent.quadbtns.button(b).ypos, 29 + parent.quadbtns.button(b).xpos, 1, 1)
+        parent.l0.addWidget(btn, 0 + parent.quadbtns.button(b).ypos,
+                            29 + parent.quadbtns.button(b).xpos, 1, 1)
         btn.setEnabled(False)
         b += 1
     parent.quadbtns.setExclusive(True)
 
+
 class QuadButton(QPushButton):
     """ custom QPushButton class for quadrant plotting
         requires buttons to put into a QButtonGroup (parent.quadbtns)
          allows only 1 button to pressed at a time
     """
+
     def __init__(self, bid, Text, parent=None):
-        super(QuadButton,self).__init__(parent)
+        super(QuadButton, self).__init__(parent)
         self.setText(Text)
         self.setCheckable(True)
         self.setStyleSheet(parent.styleInactive)
         self.setFont(QtGui.QFont("Arial", 8, QtGui.QFont.Bold))
         self.resize(self.minimumSizeHint())
         self.setMaximumWidth(22)
-        self.xpos = bid%3
-        self.ypos = int(np.floor(bid/3))
+        self.xpos = bid % 3
+        self.ypos = int(np.floor(bid / 3))
         self.clicked.connect(lambda: self.press(parent, bid))
         self.show()
+
     def press(self, parent, bid):
         for b in range(9):
             if parent.quadbtns.button(b).isEnabled():
                 parent.quadbtns.button(b).setStyleSheet(parent.styleUnpressed)
         self.setStyleSheet(parent.stylePressed)
-        self.xrange = np.array([self.xpos-.15, self.xpos+1.15]) * parent.ops['Lx']/3
-        self.yrange = np.array([self.ypos-.15, self.ypos+1.15]) * parent.ops['Ly']/3
+        self.xrange = np.array([self.xpos - .15, self.xpos + 1.15
+                               ]) * parent.ops["Lx"] / 3
+        self.yrange = np.array([self.ypos - .15, self.ypos + 1.15
+                               ]) * parent.ops["Ly"] / 3
         # change the zoom
         parent.p1.setXRange(self.xrange[0], self.xrange[1])
         parent.p1.setYRange(self.yrange[0], self.yrange[1])
@@ -107,8 +115,9 @@ def press(self, parent, bid):
 # size of view
 class SizeButton(QPushButton):
     """ buttons to make trace box bigger or smaller """
+
     def __init__(self, bid, Text, parent=None):
-        super(SizeButton,self).__init__(parent)
+        super(SizeButton, self).__init__(parent)
         self.setText(Text)
         self.setCheckable(True)
         self.setStyleSheet(parent.styleInactive)
@@ -117,30 +126,31 @@ def __init__(self, bid, Text, parent=None):
         self.clicked.connect(lambda: self.press(parent))
         self.bid = bid
         self.show()
+
     def press(self, parent):
         bid = self.bid
         for b in parent.sizebtns.buttons():
             b.setStyleSheet(parent.styleUnpressed)
         self.setStyleSheet(parent.stylePressed)
         ts = 100
-        if bid==0:
-            parent.p2.linkView(parent.p2.XAxis,view=None)
-            parent.p2.linkView(parent.p2.YAxis,view=None)
-            parent.win.ci.layout.setColumnStretchFactor(0,ts)
-            parent.win.ci.layout.setColumnStretchFactor(1,0)
-        elif bid==1:
-            parent.win.ci.layout.setColumnStretchFactor(0,ts)
-            parent.win.ci.layout.setColumnStretchFactor(1,ts)
-            parent.p2.setXLink('plot1')
-            parent.p2.setYLink('plot1')
-        elif bid==2:
-            parent.p2.linkView(parent.p2.XAxis,view=None)
-            parent.p2.linkView(parent.p2.YAxis,view=None)
-            parent.win.ci.layout.setColumnStretchFactor(0,0)
-            parent.win.ci.layout.setColumnStretchFactor(1,ts)
-        # only enable selection buttons when not in 'both' view
-        if bid!=1:
-            if parent.ops_plot['color']!=0:
+        if bid == 0:
+            parent.p2.linkView(parent.p2.XAxis, view=None)
+            parent.p2.linkView(parent.p2.YAxis, view=None)
+            parent.win.ci.layout.setColumnStretchFactor(0, ts)
+            parent.win.ci.layout.setColumnStretchFactor(1, 0)
+        elif bid == 1:
+            parent.win.ci.layout.setColumnStretchFactor(0, ts)
+            parent.win.ci.layout.setColumnStretchFactor(1, ts)
+            parent.p2.setXLink("plot1")
+            parent.p2.setYLink("plot1")
+        elif bid == 2:
+            parent.p2.linkView(parent.p2.XAxis, view=None)
+            parent.p2.linkView(parent.p2.YAxis, view=None)
+            parent.win.ci.layout.setColumnStretchFactor(0, 0)
+            parent.win.ci.layout.setColumnStretchFactor(1, ts)
+        # only enable selection buttons when not in "both" view
+        if bid != 1:
+            if parent.ops_plot["color"] != 0:
                 for btn in parent.topbtns.buttons():
                     btn.setStyleSheet(parent.styleUnpressed)
                     btn.setEnabled(True)
@@ -155,12 +165,14 @@ def press(self, parent):
         parent.win.show()
         parent.show()
 
-# 
+
+#
 class TopButton(QPushButton):
     """ selection of top neurons"""
+
     def __init__(self, bid, parent=None):
-        super(TopButton,self).__init__(parent)
-        text = [' draw selection', ' select top n', ' select bottom n']
+        super(TopButton, self).__init__(parent)
+        text = [" draw selection", " select top n", " select bottom n"]
         self.bid = bid
         self.setText(text[bid])
         self.setCheckable(True)
@@ -173,12 +185,12 @@ def __init__(self, bid, parent=None):
     def press(self, parent):
         bid = self.bid
         if not parent.sizebtns.button(1).isChecked():
-            if parent.ops_plot['color']==0:
-                for b in [1,2]:
+            if parent.ops_plot["color"] == 0:
+                for b in [1, 2]:
                     parent.topbtns.button(b).setEnabled(False)
                     parent.topbtns.button(b).setStyleSheet(parent.styleInactive)
             else:
-                for b in [1,2]:
+                for b in [1, 2]:
                     parent.topbtns.button(b).setEnabled(True)
                     parent.topbtns.button(b).setStyleSheet(parent.styleUnpressed)
         else:
@@ -186,7 +198,7 @@ def press(self, parent):
                 parent.topbtns.button(b).setEnabled(False)
                 parent.topbtns.button(b).setStyleSheet(parent.styleInactive)
         self.setStyleSheet(parent.stylePressed)
-        if bid==0:
+        if bid == 0:
             parent.ROI_selection()
         else:
             self.top_selection(parent)
@@ -208,9 +220,9 @@ def top_selection(self, parent):
             wplot = 1
             draw = True
         if draw:
-            if parent.ops_plot['color'] != 0:
-                c = parent.ops_plot['color']
-                istat = parent.colors['istat'][c]
+            if parent.ops_plot["color"] != 0:
+                c = parent.ops_plot["color"]
+                istat = parent.colors["istat"][c]
                 if wplot == 0:
                     icell = np.array(parent.iscell.nonzero()).flatten()
                     istat = istat[parent.iscell]
diff --git a/suite2p/gui/classgui.py b/suite2p/gui/classgui.py
index 7df5fd0ee..302a85cdd 100644
--- a/suite2p/gui/classgui.py
+++ b/suite2p/gui/classgui.py
@@ -9,24 +9,26 @@
 from .. import classification
 
 
-def make_buttons(parent,b0):
+def make_buttons(parent, b0):
     # ----- CLASSIFIER BUTTONS -------
     cllabel = QLabel("")
     cllabel.setFont(parent.boldfont)
     cllabel.setText("<font color='white'>Classifier</font>")
-    parent.classLabel = QLabel("<font color='white'>not loaded (using prob from iscell.npy)</font>")
+    parent.classLabel = QLabel(
+        "<font color='white'>not loaded (using prob from iscell.npy)</font>")
     parent.classLabel.setFont(QtGui.QFont("Arial", 8))
     parent.l0.addWidget(cllabel, b0, 0, 1, 2)
-    b0+=1
+    b0 += 1
     parent.l0.addWidget(parent.classLabel, b0, 0, 1, 2)
     parent.addtoclass = QPushButton(" add current data to classifier")
     parent.addtoclass.setFont(QtGui.QFont("Arial", 8, QtGui.QFont.Bold))
     parent.addtoclass.clicked.connect(lambda: add_to(parent))
     parent.addtoclass.setStyleSheet(parent.styleInactive)
-    b0+=1
+    b0 += 1
     parent.l0.addWidget(parent.addtoclass, b0, 0, 1, 2)
     return b0
 
+
 def load_classifier(parent):
     name = QFileDialog.getOpenFileName(parent, "Open File")
     if name:
@@ -35,15 +37,18 @@ def load_classifier(parent):
     else:
         print("no classifier")
 
+
 def load_s2p_classifier(parent):
     load(parent, parent.classorig)
     class_file(parent)
     parent.saveDefault.setEnabled(True)
 
+
 def load_default_classifier(parent):
     load(parent, parent.classuser)
     class_activated(parent)
 
+
 def class_file(parent):
     if parent.classfile == parent.classuser:
         cfile = "default classifier"
@@ -54,12 +59,14 @@ def class_file(parent):
     cstr = "<font color='white'>" + cfile + "</font>"
     parent.classLabel.setText(cstr)
 
+
 def class_activated(parent):
     class_file(parent)
     parent.saveDefault.setEnabled(True)
     parent.addtoclass.setStyleSheet(parent.styleUnpressed)
     parent.addtoclass.setEnabled(True)
 
+
 def class_default(parent):
     dm = QMessageBox.question(
         parent,
@@ -69,7 +76,9 @@ def class_default(parent):
     )
     if dm == QMessageBox.Yes:
         classfile = parent.classuser
-        save_model(classfile, parent.model.stats, parent.model.iscell, parent.model.keys)
+        save_model(classfile, parent.model.stats, parent.model.iscell,
+                   parent.model.keys)
+
 
 def reset_default(parent):
     dm = QMessageBox.question(
@@ -82,6 +91,7 @@ def reset_default(parent):
     if dm == QMessageBox.Yes:
         shutil.copy(parent.classorig, parent.classuser)
 
+
 def load(parent, name):
     print('loading classifier ', name)
     parent.classfile = name
@@ -89,22 +99,25 @@ def load(parent, name):
     if parent.model.loaded:
         activate(parent, True)
 
+
 def save_model(name, train_stats, train_iscell, keys):
     model = {}
-    model['stats']  = train_stats
+    model['stats'] = train_stats
     model['iscell'] = train_iscell
-    model['keys']   = keys
+    model['keys'] = keys
     print('saving classifier in ' + name)
     np.save(name, model)
 
+
 def load_list(parent):
     # will return
     LC = ListChooser('classifier training files', parent)
     result = LC.exec_()
 
-def load_data(parent,keys,trainfiles):
-    train_stats = np.zeros((0,len(keys)),np.float32)
-    train_iscell = np.zeros((0,),np.float32)
+
+def load_data(parent, keys, trainfiles):
+    train_stats = np.zeros((0, len(keys)), np.float32)
+    train_iscell = np.zeros((0,), np.float32)
     trainfiles_good = []
     loaded = False
     if trainfiles is not None:
@@ -115,91 +128,113 @@ def load_data(parent,keys,trainfiles):
                 iscells = np.load(fname)
                 ncells = iscells.shape[0]
             except (ValueError, OSError, RuntimeError, TypeError, NameError):
-                print('\t'+fname+': not a numpy array of booleans')
+                print('\t' + fname + ': not a numpy array of booleans')
                 badfile = True
             if not badfile:
                 basename, bname = os.path.split(fname)
                 lstat = 0
                 try:
-                    stat = np.load(basename+'/stat.npy', allow_pickle=True)
+                    stat = np.load(basename + '/stat.npy', allow_pickle=True)
                     ypix = stat[0]['ypix']
                     lstat = len(stat)
-                except (IndexError, KeyError, OSError, RuntimeError, TypeError, NameError):
-                    print('\t'+basename+': incorrect or missing stat.npy file :(')
+                except (IndexError, KeyError, OSError, RuntimeError, TypeError,
+                        NameError):
+                    print('\t' + basename + ': incorrect or missing stat.npy file :(')
                 if lstat != ncells:
-                    print('\t'+basename+': stat.npy is not the same length as iscell.npy')
+                    print('\t' + basename +
+                          ': stat.npy is not the same length as iscell.npy')
                 else:
                     # add iscell and stat to classifier
-                    print('\t'+fname+' was added to classifier')
-                    iscell = iscells[:,0].astype(np.float32)
-                    stats = np.reshape(np.array([stat[j][k] for j in range(len(stat)) for k in parent.default_keys]),
-                                (len(stat),-1))
-                    train_stats = np.concatenate((train_stats,stats),axis=0)
-                    train_iscell = np.concatenate((train_iscell,iscell),axis=0)
+                    print('\t' + fname + ' was added to classifier')
+                    iscell = iscells[:, 0].astype(np.float32)
+                    stats = np.reshape(
+                        np.array([
+                            stat[j][k]
+                            for j in range(len(stat))
+                            for k in parent.default_keys
+                        ]), (len(stat), -1))
+                    train_stats = np.concatenate((train_stats, stats), axis=0)
+                    train_iscell = np.concatenate((train_iscell, iscell), axis=0)
                     trainfiles_good.append(fname)
     if len(trainfiles_good) > 0:
-        classfile, saved = save(parent,train_stats,train_iscell,keys)
+        classfile, saved = save(parent, train_stats, train_iscell, keys)
         if saved:
             parent.classfile = classfile
             loaded = True
         else:
-            msg = QMessageBox.information(parent,'Incorrect file path',
-                                                'Incorrect save path for classifier, classifier not built.')
+            msg = QMessageBox.information(
+                parent, 'Incorrect file path',
+                'Incorrect save path for classifier, classifier not built.')
     else:
-        msg = QMessageBox.information(parent,'Incorrect files',
-                                            'No valid datasets chosen to build classifier, classifier not built.')
+        msg = QMessageBox.information(
+            parent, 'Incorrect files',
+            'No valid datasets chosen to build classifier, classifier not built.')
     return loaded
 
+
 def add_to(parent):
-    fname = parent.basename+'/iscell.npy'
+    fname = parent.basename + '/iscell.npy'
     print('Adding current dataset to classifier')
     if parent.classfile == parent.classuser:
         cfile = 'the default classifier'
     else:
         cfile = parent.classfile
-    dm = QMessageBox.question(parent,'Default classifier',
-                                    'Current classifier is '+cfile+'. Add to this classifier?',
-                                    QMessageBox.Yes | QMessageBox.No)
+    dm = QMessageBox.question(
+        parent, 'Default classifier',
+        'Current classifier is ' + cfile + '. Add to this classifier?',
+        QMessageBox.Yes | QMessageBox.No)
     if dm == QMessageBox.Yes:
-        stats = np.reshape(np.array([parent.stat[j][k] for j in range(len(parent.stat)) for k in parent.model.keys]),
-                                (len(parent.stat),-1))
-        parent.model.stats = np.concatenate((parent.model.stats,stats),axis=0)
-        parent.model.iscell = np.concatenate((parent.model.iscell,parent.iscell),axis=0)
-        save_model(parent.classfile, parent.model.stats, parent.model.iscell, parent.model.keys)
+        stats = np.reshape(
+            np.array([
+                parent.stat[j][k]
+                for j in range(len(parent.stat))
+                for k in parent.model.keys
+            ]), (len(parent.stat), -1))
+        parent.model.stats = np.concatenate((parent.model.stats, stats), axis=0)
+        parent.model.iscell = np.concatenate((parent.model.iscell, parent.iscell),
+                                             axis=0)
+        save_model(parent.classfile, parent.model.stats, parent.model.iscell,
+                   parent.model.keys)
         activate(parent, True)
-        msg = QMessageBox.information(parent,'Classifier saved and loaded',
-                                            'Current dataset added to classifier, and cell probabilities computed and in GUI')
+        msg = QMessageBox.information(
+            parent, 'Classifier saved and loaded',
+            'Current dataset added to classifier, and cell probabilities computed and in GUI'
+        )
 
 
 def save(parent, train_stats, train_iscell, keys):
-    name = QFileDialog.getSaveFileName(parent,'Classifier name (*.npy)')
+    name = QFileDialog.getSaveFileName(parent, 'Classifier name (*.npy)')
     name = name[0]
     saved = False
     if name:
         try:
             save_model(name, train_stats, train_iscell, keys)
             saved = True
-        except (OSError, RuntimeError, TypeError, NameError,FileNotFoundError):
+        except (OSError, RuntimeError, TypeError, NameError, FileNotFoundError):
             print('ERROR: incorrect filename for saving')
     return name, saved
 
+
 def save_list(parent):
-    name = QFileDialog.getSaveFileName(parent,'Save list of iscell.npy')
+    name = QFileDialog.getSaveFileName(parent, 'Save list of iscell.npy')
     if name:
         try:
-            with open(name[0],'w') as fid:
+            with open(name[0], 'w') as fid:
                 for f in parent.trainfiles:
                     fid.write(f)
                     fid.write('\n')
-        except (ValueError, OSError, RuntimeError, TypeError, NameError,FileNotFoundError):
+        except (ValueError, OSError, RuntimeError, TypeError, NameError,
+                FileNotFoundError):
             print('ERROR: incorrect filename for saving')
 
+
 def activate(parent, inactive):
     if inactive:
         parent.probcell = parent.model.predict_proba(parent.stat)
     class_masks(parent)
     parent.update_plot()
 
+
 def disable(parent):
     parent.classbtn.setEnabled(False)
     parent.saveClass.setEnabled(False)
@@ -207,51 +242,54 @@ def disable(parent):
     for btns in parent.classbtns.buttons():
         btns.setEnabled(False)
 
+
 ### custom QDialog which makes a list of items you can include/exclude
 class ListChooser(QDialog):
+
     def __init__(self, Text, parent=None):
         super(ListChooser, self).__init__(parent)
-        self.setGeometry(300,300,500,320)
+        self.setGeometry(300, 300, 500, 320)
         self.setWindowTitle(Text)
         self.win = QWidget(self)
         layout = QGridLayout()
         self.win.setLayout(layout)
         #self.setCentralWidget(self.win)
         loadcell = QPushButton('Load iscell.npy')
-        loadcell.resize(200,50)
+        loadcell.resize(200, 50)
         loadcell.clicked.connect(self.load_cell)
-        layout.addWidget(loadcell,0,0,1,1)
+        layout.addWidget(loadcell, 0, 0, 1, 1)
         loadtext = QPushButton('Load txt file list')
         loadtext.clicked.connect(self.load_text)
-        layout.addWidget(loadtext,0,1,1,1)
-        layout.addWidget(QLabel('(select multiple using ctrl)'),1,0,1,1)
+        layout.addWidget(loadtext, 0, 1, 1, 1)
+        layout.addWidget(QLabel('(select multiple using ctrl)'), 1, 0, 1, 1)
         self.list = QListWidget(parent)
-        layout.addWidget(self.list,2,0,5,4)
+        layout.addWidget(self.list, 2, 0, 5, 4)
         #self.list.resize(450,250)
         self.list.setSelectionMode(QAbstractItemView.MultiSelection)
         save = QPushButton('build classifier')
         save.clicked.connect(lambda: self.build_classifier(parent))
-        layout.addWidget(save,8,0,1,1)
+        layout.addWidget(save, 8, 0, 1, 1)
         self.apply = QPushButton('load in GUI')
         self.apply.clicked.connect(lambda: self.apply_class(parent))
         self.apply.setEnabled(False)
-        layout.addWidget(self.apply,8,1,1,1)
+        layout.addWidget(self.apply, 8, 1, 1, 1)
         self.saveasdefault = QPushButton('save as default')
         self.saveasdefault.clicked.connect(lambda: self.save_default(parent))
         self.saveasdefault.setEnabled(False)
-        layout.addWidget(self.saveasdefault,8,2,1,1)
+        layout.addWidget(self.saveasdefault, 8, 2, 1, 1)
         done = QPushButton('close')
         done.clicked.connect(self.exit_list)
-        layout.addWidget(done,8,3,1,1)
+        layout.addWidget(done, 8, 3, 1, 1)
 
     def load_cell(self):
-        name = QFileDialog.getOpenFileName(self, 'Open iscell.npy file',filter='iscell.npy')
+        name = QFileDialog.getOpenFileName(self, 'Open iscell.npy file',
+                                           filter='iscell.npy')
         if name:
             try:
                 iscell = np.load(name[0])
                 badfile = True
                 if iscell.shape[0] > 0:
-                    if iscell[0,0]==0 or iscell[0,0]==1:
+                    if iscell[0, 0] == 0 or iscell[0, 0] == 1:
                         badfile = False
                         self.list.addItem(name[0])
                 if badfile:
@@ -262,7 +300,8 @@ def load_cell(self):
             QMessageBox.information(self, 'iscell.npy should be 0/1')
 
     def load_text(self):
-        name = QFileDialog.getOpenFileName(self, 'Open *.txt file', filter='text file (*.txt)')
+        name = QFileDialog.getOpenFileName(self, 'Open *.txt file',
+                                           filter='text file (*.txt)')
         if name:
             try:
                 txtfile = open(name[0], 'r')
@@ -277,20 +316,21 @@ def load_text(self):
 
     def build_classifier(self, parent):
         parent.trainfiles = []
-        i=0
+        i = 0
         for item in self.list.selectedItems():
             parent.trainfiles.append(item.text())
-            i+=1
-        if i==0:
+            i += 1
+        if i == 0:
             for r in range(self.list.count()):
                 parent.trainfiles.append(self.list.item(r).text())
-        if len(parent.trainfiles)>0:
+        if len(parent.trainfiles) > 0:
             print('Populating classifier:')
             keys = parent.default_keys
             loaded = load_data(parent, keys, parent.trainfiles)
             if loaded:
-                msg = QMessageBox.information(parent,'Classifier saved',
-                                                    'Classifier built from valid files and saved.')
+                msg = QMessageBox.information(
+                    parent, 'Classifier saved',
+                    'Classifier built from valid files and saved.')
                 self.apply.setEnabled(True)
                 self.saveasdefault.setEnabled(True)
 
@@ -299,9 +339,10 @@ def apply_class(self, parent):
         activate(parent, True)
 
     def save_default(self, parent):
-        dm = QMessageBox.question(self,'Default classifier',
-                                        'Are you sure you want to overwrite your default classifier?',
-                                        QMessageBox.Yes | QMessageBox.No)
+        dm = QMessageBox.question(
+            self, 'Default classifier',
+            'Are you sure you want to overwrite your default classifier?',
+            QMessageBox.Yes | QMessageBox.No)
         if dm == QMessageBox.Yes:
             shutil.copy(parent.classfile, parent.classuser)
 
@@ -312,11 +353,14 @@ def exit_list(self):
 def class_masks(parent):
     c = 6
     istat = parent.probcell
-    parent.colors['colorbar'][c] = [istat.min(), (istat.max()-istat.min())/2, istat.max()]
+    parent.colors['colorbar'][c] = [
+        istat.min(), (istat.max() - istat.min()) / 2,
+        istat.max()
+    ]
     istat = istat - istat.min()
     istat = istat / istat.max()
     col = masks.istat_transform(istat, parent.ops_plot['colormap'])
     parent.colors['cols'][c] = col
     parent.colors['istat'][c] = istat.flatten()
 
-    masks.rgb_masks(parent, col, c)
\ No newline at end of file
+    masks.rgb_masks(parent, col, c)
diff --git a/suite2p/gui/drawroi.py b/suite2p/gui/drawroi.py
index 381320ead..62f68842e 100644
--- a/suite2p/gui/drawroi.py
+++ b/suite2p/gui/drawroi.py
@@ -16,71 +16,73 @@
 
 
 def masks_and_traces(ops, stat_manual, stat_orig):
-    ''' main extraction function
+    """ main extraction function
         inputs: ops and stat
         creates cell and neuropil masks and extracts traces
         returns: F (ROIs x time), Fneu (ROIs x time), F_chan2, Fneu_chan2, ops, stat
         F_chan2 and Fneu_chan2 will be empty if no second channel
-    '''
+    """
 
     t0 = time.time()
     # Concatenate stat so a good neuropil function can be formed
     stat_all = stat_manual.copy()
     for n in range(len(stat_orig)):
         stat_all.append(stat_orig[n])
-    
-    stat_all = roi_stats(stat_all, ops['Ly'], ops['Lx'], aspect=ops.get('aspect', None), diameter=ops['diameter'])
+
+    stat_all = roi_stats(stat_all, ops["Ly"], ops["Lx"], aspect=ops.get("aspect", None),
+                         diameter=ops["diameter"])
     cell_masks = [
-        masks.create_cell_mask(stat, Ly=ops['Ly'], Lx=ops['Lx'], allow_overlap=ops['allow_overlap']) for stat in stat_all
+        masks.create_cell_mask(stat, Ly=ops["Ly"], Lx=ops["Lx"],
+                               allow_overlap=ops["allow_overlap"]) for stat in stat_all
     ]
-    cell_pix = masks.create_cell_pix(stat_all, Ly=ops['Ly'], Lx=ops['Lx'])
+    cell_pix = masks.create_cell_pix(stat_all, Ly=ops["Ly"], Lx=ops["Lx"])
     manual_roi_stats = stat_all[:len(stat_manual)]
     manual_cell_masks = cell_masks[:len(stat_manual)]
     manual_neuropil_masks = masks.create_neuropil_masks(
-        ypixs=[stat['ypix'] for stat in manual_roi_stats],
-        xpixs=[stat['xpix'] for stat in manual_roi_stats],
+        ypixs=[stat["ypix"] for stat in manual_roi_stats],
+        xpixs=[stat["xpix"] for stat in manual_roi_stats],
         cell_pix=cell_pix,
-        inner_neuropil_radius=ops['inner_neuropil_radius'],
-        min_neuropil_pixels=ops['min_neuropil_pixels'],
+        inner_neuropil_radius=ops["inner_neuropil_radius"],
+        min_neuropil_pixels=ops["min_neuropil_pixels"],
     )
-    print('Masks made in %0.2f sec.' % (time.time() - t0))
+    print("Masks made in %0.2f sec." % (time.time() - t0))
 
-    F, Fneu, F_chan2, Fneu_chan2 = extract_traces_from_masks(ops, 
-                                                             manual_cell_masks, 
+    F, Fneu, F_chan2, Fneu_chan2 = extract_traces_from_masks(ops, manual_cell_masks,
                                                              manual_neuropil_masks)
 
     # compute activity statistics for classifier
-    npix = np.array([stat_orig[n]['npix'] for n in range(len(stat_orig))]).astype('float32')
+    npix = np.array([stat_orig[n]["npix"] for n in range(len(stat_orig))
+                    ]).astype("float32")
     for n in range(len(manual_roi_stats)):
-        manual_roi_stats[n]['npix_norm'] = manual_roi_stats[n]['npix'] / np.mean(npix[:100])  # What if there are less than 100 cells?
-        manual_roi_stats[n]['compact'] = 1
-        manual_roi_stats[n]['footprint'] = 2
-        manual_roi_stats[n]['manual'] = 1  # Add manual key
+        manual_roi_stats[n]["npix_norm"] = manual_roi_stats[n]["npix"] / np.mean(
+            npix[:100])  # What if there are less than 100 cells?
+        manual_roi_stats[n]["compact"] = 1
+        manual_roi_stats[n]["footprint"] = 2
+        manual_roi_stats[n]["manual"] = 1  # Add manual key
 
     # subtract neuropil and compute skew, std from F
-    dF = F - ops['neucoeff'] * Fneu
+    dF = F - ops["neucoeff"] * Fneu
     sk = stats.skew(dF, axis=1)
     sd = np.std(dF, axis=1)
 
     for n in range(F.shape[0]):
-        manual_roi_stats[n]['skew'] = sk[n]
-        manual_roi_stats[n]['std'] = sd[n]
-        manual_roi_stats[n]['med'] = [np.mean(manual_roi_stats[n]['ypix']), np.mean(manual_roi_stats[n]['xpix'])]
-
-    dF = preprocess(
-                F=dF,
-                baseline=ops['baseline'],
-                win_baseline=ops['win_baseline'],
-                sig_baseline=ops['sig_baseline'],
-                fs=ops['fs'],
-                prctile_baseline=ops['prctile_baseline']
-            )
-    spks = oasis(F=dF, batch_size=ops['batch_size'], tau=ops['tau'], fs=ops['fs'])
+        manual_roi_stats[n]["skew"] = sk[n]
+        manual_roi_stats[n]["std"] = sd[n]
+        manual_roi_stats[n]["med"] = [
+            np.mean(manual_roi_stats[n]["ypix"]),
+            np.mean(manual_roi_stats[n]["xpix"])
+        ]
+
+    dF = preprocess(F=dF, baseline=ops["baseline"], win_baseline=ops["win_baseline"],
+                    sig_baseline=ops["sig_baseline"], fs=ops["fs"],
+                    prctile_baseline=ops["prctile_baseline"])
+    spks = oasis(F=dF, batch_size=ops["batch_size"], tau=ops["tau"], fs=ops["fs"])
 
     return F, Fneu, F_chan2, Fneu_chan2, spks, ops, manual_roi_stats
 
 
 class ViewButton(QPushButton):
+
     def __init__(self, bid, Text, parent=None):
         super(ViewButton, self).__init__(parent)
         self.setText(Text)
@@ -104,12 +106,13 @@ def press(self, parent, bid):
 
 
 class ROIDraw(QMainWindow):
+
     def __init__(self, parent):
         super(ROIDraw, self).__init__(parent)
-        pg.setConfigOptions(imageAxisOrder='row-major')
+        pg.setConfigOptions(imageAxisOrder="row-major")
         self.parent = parent
         self.setGeometry(70, 70, 1400, 800)
-        self.setWindowTitle('extract ROI activity')
+        self.setWindowTitle("extract ROI activity")
         self.cwidget = QWidget(self)
         self.setCentralWidget(self.cwidget)
         self.l0 = QGridLayout()
@@ -122,7 +125,7 @@ def __init__(self, parent):
                                "background-color: rgb(50,50,50); "
                                "color:white;}")
 
-        # self.p0 = pg.ViewBox(lockAspect=False,name='plot1',border=[100,100,100],invertY=True)
+        # self.p0 = pg.ViewBox(lockAspect=False,name="plot1",border=[100,100,100],invertY=True)
         self.win = pg.GraphicsLayoutWidget()
         # --- cells image
         self.win = pg.GraphicsLayoutWidget()
@@ -134,7 +137,8 @@ def __init__(self, parent):
         self.p1.setMenuEnabled(False)
         self.p1.scene().sigMouseMoved.connect(self.mouse_moved)
 
-        self.p0 = self.win.addViewBox(name='plot1', lockAspect=True, row=0, col=0, invertY=True)
+        self.p0 = self.win.addViewBox(name="plot1", lockAspect=True, row=0, col=0,
+                                      invertY=True)
         self.img0 = pg.ImageItem()
         self.p0.addItem(self.img0)
 
@@ -154,7 +158,7 @@ def __init__(self, parent):
         self.addROI.setFixedWidth(60)
         self.addROI.setStyleSheet(self.styleUnpressed)
         self.l0.addWidget(self.addROI, 2, 0, 1, 1)
-        lbl = QLabel('diameter:')
+        lbl = QLabel("diameter:")
         lbl.setFont(QtGui.QFont("Arial", 8, QtGui.QFont.Bold))
         lbl.setStyleSheet("color: white;")
         lbl.setFixedWidth(60)
@@ -188,10 +192,10 @@ def __init__(self, parent):
         self.l0.addWidget(self.closeGUI, 0, 5, 1, 1)
 
         # view buttons
-        self.views = ["W: mean img",
-                      "E: mean img (enhanced)",
-                      "R: correlation map",
-                      "T: max projection"]
+        self.views = [
+            "W: mean img", "E: mean img (enhanced)", "R: correlation map",
+            "T: max projection"
+        ]
         b = 0
         self.viewbtns = QButtonGroup(self)
         for names in self.views:
@@ -206,8 +210,8 @@ def __init__(self, parent):
 
         self.l0.addWidget(QLabel("neuropil"), 13, 13, 1, 1)
 
-        self.Ly = self.parent.ops['Ly']
-        self.Lx = self.parent.ops['Lx']
+        self.Ly = self.parent.ops["Ly"]
+        self.Lx = self.parent.ops["Lx"]
         self.iscell = self.parent.iscell
 
         # Get maskf for pixels that are cells
@@ -216,16 +220,16 @@ def __init__(self, parent):
         self.img0.setImage(self.masked_images[:, :, :, 0])
 
     def closeEvent(self, event):
-        print('closing GUI')
-        # if user didn't click "save & quit" button
+        print("closing GUI")
+        # if user didn"t click "save & quit" button
         if not self.saveGUI:
             self.check_proc(event)
 
     def check_proc(self, event):
         cproc = QMessageBox.question(
-            self, "PROC", 'Would you like to save traces before closing? (if you havent extracted the traces, click Cancel and extract!)', 
-            QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel 
-        )
+            self, "PROC",
+            "Would you like to save traces before closing? (if you havent extracted the traces, click Cancel and extract!)",
+            QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
         if cproc == QMessageBox.Yes:
             self.close_GUI()
         elif cproc == QMessageBox.Cancel:
@@ -233,49 +237,51 @@ def check_proc(self, event):
 
     def close_GUI(self):
         # Replace old stat file
-        print('Saving old stat')
-        np.save(os.path.join(self.parent.basename, 'stat_orig.npy'), self.parent.stat)
+        print("Saving old stat")
+        np.save(os.path.join(self.parent.basename, "stat_orig.npy"), self.parent.stat)
 
         # Save iscell
-        print('Num cells', self.nROIs)
+        print("Num cells", self.nROIs)
 
         # Append new stat file with old and save
-        print('Saving new stat')
+        print("Saving new stat")
         stat_all = self.new_stat.copy()
         for n in range(len(self.parent.stat)):
             stat_all.append(self.parent.stat[n])
-        np.save(os.path.join(self.parent.basename, 'stat.npy'), stat_all)
-        iscell_prob = np.concatenate((self.parent.iscell[:, np.newaxis], self.parent.probcell[:, np.newaxis]), axis=1)
+        np.save(os.path.join(self.parent.basename, "stat.npy"), stat_all)
+        iscell_prob = np.concatenate(
+            (self.parent.iscell[:, np.newaxis], self.parent.probcell[:, np.newaxis]),
+            axis=1)
 
         new_iscell = np.ones((self.nROIs, 2))
-        new_iscell = np.concatenate((new_iscell, iscell_prob),
-                                    axis=0)
-        np.save(os.path.join(self.parent.basename, 'iscell.npy'), new_iscell)
+        new_iscell = np.concatenate((new_iscell, iscell_prob), axis=0)
+        np.save(os.path.join(self.parent.basename, "iscell.npy"), new_iscell)
 
         # Save fluorescence traces
         Fcell = np.concatenate((self.Fcell, self.parent.Fcell), axis=0)
         Fneu = np.concatenate((self.Fneu, self.parent.Fneu), axis=0)
-        Spks = np.concatenate((self.Spks, self.parent.Spks),
-                              axis=0)  # For now convert spikes to 0 for the new ROIS and then fix it later
-        np.save(os.path.join(self.parent.basename, 'F.npy'), Fcell)
-        np.save(os.path.join(self.parent.basename, 'Fneu.npy'), Fneu)
-        np.save(os.path.join(self.parent.basename, 'spks.npy'), Spks)
-
-        if 'reg_file_chan2' in self.parent.ops:
-            F_chan2 = np.load(os.path.join(self.parent.basename, 'F_chan2.npy'))
-            Fneu_chan2 = np.load(os.path.join(self.parent.basename, 'Fneu_chan2.npy'))
-            redorig = np.load(os.path.join(self.parent.basename, 'redcell.npy'))
+        Spks = np.concatenate(
+            (self.Spks, self.parent.Spks), axis=0
+        )  # For now convert spikes to 0 for the new ROIS and then fix it later
+        np.save(os.path.join(self.parent.basename, "F.npy"), Fcell)
+        np.save(os.path.join(self.parent.basename, "Fneu.npy"), Fneu)
+        np.save(os.path.join(self.parent.basename, "spks.npy"), Spks)
+
+        if "reg_file_chan2" in self.parent.ops:
+            F_chan2 = np.load(os.path.join(self.parent.basename, "F_chan2.npy"))
+            Fneu_chan2 = np.load(os.path.join(self.parent.basename, "Fneu_chan2.npy"))
+            redorig = np.load(os.path.join(self.parent.basename, "redcell.npy"))
             F_chan2 = np.concatenate((self.F_chan2, F_chan2), axis=0)
             Fneu_chan2 = np.concatenate((self.Fneu_chan2, Fneu_chan2), axis=0)
             Fneu = np.concatenate((self.Fneu, self.parent.Fneu), axis=0)
             new_redcell = np.zeros((self.nROIs, 2))
-            new_redcell = np.concatenate((new_redcell, redorig),
-                                    axis=0)
-            np.save(os.path.join(self.parent.basename, 'F_chan2.npy'), F_chan2)
-            np.save(os.path.join(self.parent.basename, 'Fneu_chan2.npy'), Fneu_chan2)
-            np.save(os.path.join(self.parent.basename, 'redcell.npy'), new_redcell)
+            new_redcell = np.concatenate((new_redcell, redorig), axis=0)
+            np.save(os.path.join(self.parent.basename, "F_chan2.npy"), F_chan2)
+            np.save(os.path.join(self.parent.basename, "Fneu_chan2.npy"), Fneu_chan2)
+            np.save(os.path.join(self.parent.basename, "redcell.npy"), new_redcell)
 
-        print(np.shape(Fcell), np.shape(Fneu), np.shape(Spks), np.shape(new_iscell), np.shape(stat_all))
+        print(np.shape(Fcell), np.shape(Fneu), np.shape(Spks), np.shape(new_iscell),
+              np.shape(stat_all))
 
         # close GUI
         io.load_proc(self.parent)
@@ -283,30 +289,37 @@ def close_GUI(self):
         self.close()
 
     def normalize_img_add_masks(self):
-        masked_image = np.zeros(((self.Ly, self.Lx, 3, 4)))  # 3 for RGB and 4 for buttons
+        masked_image = np.zeros(
+            ((self.Ly, self.Lx, 3, 4)))  # 3 for RGB and 4 for buttons
         for i in np.arange(4):  # 4 because 4 buttons
             if i == 0:
                 mimg = np.zeros((self.Ly, self.Lx), np.float32)
-                mimg[self.parent.ops['yrange'][0]:self.parent.ops['yrange'][1],
-                    self.parent.ops['xrange'][0]:self.parent.ops['xrange'][1]] = self.parent.ops['meanImg'][self.parent.ops['yrange'][0]:self.parent.ops['yrange'][1],
-                                                                                                            self.parent.ops['xrange'][0]:self.parent.ops['xrange'][1]]
-                
+                mimg[self.parent.ops["yrange"][0]:self.parent.ops["yrange"][1],
+                     self.parent.ops["xrange"][0]:self.parent.
+                     ops["xrange"][1]] = self.parent.ops["meanImg"][
+                         self.parent.ops["yrange"][0]:self.parent.ops["yrange"][1],
+                         self.parent.ops["xrange"][0]:self.parent.ops["xrange"][1]]
+
             elif i == 1:
                 mimg = np.zeros((self.Ly, self.Lx), np.float32)
-                mimg[self.parent.ops['yrange'][0]:self.parent.ops['yrange'][1],
-                    self.parent.ops['xrange'][0]:self.parent.ops['xrange'][1]] = self.parent.ops['meanImgE'][self.parent.ops['yrange'][0]:self.parent.ops['yrange'][1],
-                                                                                                            self.parent.ops['xrange'][0]:self.parent.ops['xrange'][1]]
+                mimg[self.parent.ops["yrange"][0]:self.parent.ops["yrange"][1],
+                     self.parent.ops["xrange"][0]:self.parent.
+                     ops["xrange"][1]] = self.parent.ops["meanImgE"][
+                         self.parent.ops["yrange"][0]:self.parent.ops["yrange"][1],
+                         self.parent.ops["xrange"][0]:self.parent.ops["xrange"][1]]
             elif i == 2:
                 mimg = np.zeros((self.Ly, self.Lx), np.float32)
-                mimg[self.parent.ops['yrange'][0]:self.parent.ops['yrange'][1],
-                    self.parent.ops['xrange'][0]:self.parent.ops['xrange'][1]] = self.parent.ops['Vcorr']
-                
+                mimg[self.parent.ops["yrange"][0]:self.parent.ops["yrange"][1],
+                     self.parent.ops["xrange"][0]:self.parent.
+                     ops["xrange"][1]] = self.parent.ops["Vcorr"]
+
             else:
                 mimg = np.zeros((self.Ly, self.Lx), np.float32)
-                if 'max_proj' in self.parent.ops:
-                    mimg[self.parent.ops['yrange'][0]:self.parent.ops['yrange'][1],
-                        self.parent.ops['xrange'][0]:self.parent.ops['xrange'][1]] = self.parent.ops['max_proj']
-                
+                if "max_proj" in self.parent.ops:
+                    mimg[self.parent.ops["yrange"][0]:self.parent.ops["yrange"][1],
+                         self.parent.ops["xrange"][0]:self.parent.
+                         ops["xrange"][1]] = self.parent.ops["max_proj"]
+
             mimg1 = np.percentile(mimg, 1)
             mimg99 = np.percentile(mimg, 99)
             mimg = (mimg - mimg1) / (mimg99 - mimg1)
@@ -318,18 +331,18 @@ def normalize_img_add_masks(self):
     def create_masks_of_cells(self, mean_img):
         H = np.zeros_like(mean_img)
         S = np.zeros_like(mean_img)
-        columncol = self.parent.colors['istat'][0]
+        columncol = self.parent.colors["istat"][0]
 
         for n in np.arange(np.shape(self.parent.iscell)[0]):
             if self.parent.iscell[n] == 1:
-                ypix = self.parent.stat[n]['ypix'].flatten()
-                xpix = self.parent.stat[n]['xpix'].flatten()
+                ypix = self.parent.stat[n]["ypix"].flatten()
+                xpix = self.parent.stat[n]["xpix"].flatten()
                 H[ypix, xpix] = np.random.rand()
                 S[ypix, xpix] = 1
 
-        pix = np.concatenate(((H[:, :, np.newaxis]),
-                              S[:, :, np.newaxis],
-                              mean_img[:, :, np.newaxis]), axis=-1)
+        pix = np.concatenate(
+            ((H[:, :, np.newaxis]), S[:, :, np.newaxis], mean_img[:, :, np.newaxis]),
+            axis=-1)
         pix = hsv_to_rgb(pix)
         return pix
 
@@ -342,7 +355,8 @@ def mouse_moved(self, pos):
                 # print(self.ineuron)
 
     def keyPressEvent(self, event):
-        if event.modifiers() != QtCore.Qt.AltModifier and event.modifiers() != QtCore.Qt.ShiftModifier:
+        if event.modifiers() != QtCore.Qt.AltModifier and event.modifiers(
+        ) != QtCore.Qt.ShiftModifier:
             if event.key() == QtCore.Qt.Key_D:
                 self.ROIs[self.iROI].remove(self)
             elif event.key() == QtCore.Qt.Key_W:
@@ -361,10 +375,11 @@ def keyPressEvent(self, event):
     def add_ROI(self, pos=None):
         self.iROI = len(self.ROIs)
         self.nROIs = len(self.ROIs)
-        self.ROIs.append(sROI(iROI=self.nROIs, parent=self, pos=pos, diameter=int(self.diam.text())))
+        self.ROIs.append(
+            sROI(iROI=self.nROIs, parent=self, pos=pos, diameter=int(self.diam.text())))
         self.ROIs[-1].position(self)
         self.nROIs += 1
-        print('%d cells added to manual GUI'%self.nROIs)
+        print("%d cells added to manual GUI" % self.nROIs)
         self.closeGUI.setEnabled(False)
 
     def plot_clicked(self, event):
@@ -375,8 +390,11 @@ def plot_clicked(self, event):
                 posy = pos.x()
                 posx = pos.y()
                 if event.modifiers() == QtCore.Qt.AltModifier:
-                    self.add_ROI(pos=np.array([posx - 5, posy - 5,
-                                               int(self.diam.text()), int(self.diam.text())]))
+                    self.add_ROI(pos=np.array([
+                        posx - 5, posy - 5,
+                        int(self.diam.text()),
+                        int(self.diam.text())
+                    ]))
                 if event.double():
                     self.p0.setXRange(0, self.Lx)
                     self.p0.setYRange(0, self.Ly)
@@ -402,17 +420,25 @@ def proc_ROI(self):
             ypix = y[ellipse].flatten()
             xpix = x[ellipse].flatten()
             lam = np.ones(ypix.shape)
-            stat0.append({'ypix': ypix, 'xpix': xpix, 'lam': lam, 'npix': ypix.size, 'med': med})
+            stat0.append({
+                "ypix": ypix,
+                "xpix": xpix,
+                "lam": lam,
+                "npix": ypix.size,
+                "med": med
+            })
             self.tlabel.append(pg.TextItem(str(n), self.ROIs[n].color, anchor=(0, 0)))
             self.tlabel[-1].setPos(xpix.mean(), ypix.mean())
             self.p0.addItem(self.tlabel[-1])
-            self.scatter.append(pg.ScatterPlotItem([xpix.mean()], [ypix.mean()],
-                                                   pen=self.ROIs[n].color, symbol='+'))
+            self.scatter.append(
+                pg.ScatterPlotItem([xpix.mean()], [ypix.mean()], pen=self.ROIs[n].color,
+                                   symbol="+"))
             self.p0.addItem(self.scatter[-1])
-        if not os.path.isfile(self.parent.ops['reg_file']):
-            self.parent.ops['reg_file'] = os.path.join(self.parent.basename, 'data.bin')
+        if not os.path.isfile(self.parent.ops["reg_file"]):
+            self.parent.ops["reg_file"] = os.path.join(self.parent.basename, "data.bin")
 
-        F, Fneu, F_chan2, Fneu_chan2, spks, ops, stat = masks_and_traces(self.parent.ops, stat0, self.parent.stat)
+        F, Fneu, F_chan2, Fneu_chan2, spks, ops, stat = masks_and_traces(
+            self.parent.ops, stat0, self.parent.stat)
         self.Fcell = F
         self.Fneu = Fneu
         self.F_chan2 = F_chan2
@@ -427,7 +453,7 @@ def plot_trace(self):
         self.trange = np.arange(0, self.Fcell.shape[1])
         self.p1.clear()
         kspace = 1.0
-        ax = self.p1.getAxis('left')
+        ax = self.p1.getAxis("left")
         favg = 0
         k = self.nROIs - 1
         ttick = list()
@@ -442,7 +468,7 @@ def plot_trace(self):
             self.p1.plot(self.trange, f + k * kspace, pen=rgb)
             fneu = (fneu - fmin) / (fmax - fmin)
             if self.nROIs == 1:
-                self.p1.plot(self.trange, fneu + k * kspace, pen='r')
+                self.p1.plot(self.trange, fneu + k * kspace, pen="r")
             ttick.append((k * kspace + f.mean(), str(n)))
             k -= 1
         self.fmax = (self.nROIs - 1) * kspace + 1
@@ -453,6 +479,7 @@ def plot_trace(self):
 
 
 class sROI():
+
     def __init__(self, iROI, parent=None, pos=None, diameter=None, color=None,
                  yrange=None, xrange=None):
         # what type of ROI it is
@@ -492,8 +519,7 @@ def __init__(self, iROI, parent=None, pos=None, diameter=None, color=None,
         self.ROI.sigRemoveRequested.connect(lambda: self.remove(parent))
 
     def draw(self, parent, imy, imx, dy, dx):
-        roipen = pg.mkPen(self.color, width=3,
-                          style=QtCore.Qt.SolidLine)
+        roipen = pg.mkPen(self.color, width=3, style=QtCore.Qt.SolidLine)
         self.ROI = pg.EllipseROI([imx, imy], [dx, dy], pen=roipen, removable=True)
         self.ROI.handleSize = 8
         self.ROI.handlePen = roipen
@@ -528,8 +554,8 @@ def position(self, parent):
         br = self.ROI.boundingRect()
         ellipse = np.zeros((yrange.size, xrange.size), "bool")
         x, y = np.meshgrid(np.arange(0, xrange.size, 1), np.arange(0, yrange.size, 1))
-        ellipse = ((y - br.center().y()) ** 2 / (br.height() / 2) ** 2 +
-                   (x - br.center().x()) ** 2 / (br.width() / 2) ** 2) <= 1
+        ellipse = ((y - br.center().y())**2 / (br.height() / 2)**2 +
+                   (x - br.center().x())**2 / (br.width() / 2)**2) <= 1
 
         ellipse = ellipse[:, np.logical_and(xrange >= 0, xrange < parent.Lx)]
         xrange = xrange[np.logical_and(xrange >= 0, xrange < parent.Lx)]
@@ -539,4 +565,4 @@ def position(self, parent):
         # ellipse = lambda x,y: (((x+0.5)/(w/2.)-1)**2+ ((y+0.5)/(h/2.)-1)**2)**0.5 < 1, (w, h))
         self.ellipse = ellipse
         self.xrange = xrange
-        self.yrange = yrange
\ No newline at end of file
+        self.yrange = yrange
diff --git a/suite2p/gui/graphics.py b/suite2p/gui/graphics.py
index 18287efda..8c8edafcf 100644
--- a/suite2p/gui/graphics.py
+++ b/suite2p/gui/graphics.py
@@ -9,7 +9,9 @@
 
 
 class TraceBox(pg.PlotItem):
-    def __init__(self, parent=None, border=None, lockAspect=False, enableMouse=True, invertY=False, enableMenu=True, name=None, invertX=False):
+
+    def __init__(self, parent=None, border=None, lockAspect=False, enableMouse=True,
+                 invertY=False, enableMenu=True, name=None, invertX=False):
         super(TraceBox, self).__init__()
         self.parent = parent
 
@@ -21,24 +23,26 @@ def zoom_plot(self):
         self.setYRange(self.parent.fmin, self.parent.fmax)
         self.parent.show()
 
+
 class ViewBox(pg.ViewBox):
+
     def __init__(self, parent=None, border=None, lockAspect=False, enableMouse=True,
                  invertY=False, enableMenu=True, name=None, invertX=False):
         #pg.ViewBox.__init__(self, border, lockAspect, enableMouse,
-                            #invertY, enableMenu, name, invertX)
+        #invertY, enableMenu, name, invertX)
         super(ViewBox, self).__init__()
         self.border = fn.mkPen(border)
         if enableMenu:
             self.menu = ViewBoxMenu(self)
         self.name = name
-        self.parent=parent
-        if self.name=="plot2":
+        self.parent = parent
+        if self.name == "plot2":
             self.setXLink(parent.p1)
             self.setYLink(parent.p1)
 
         # set state
-        self.state['enableMenu'] = enableMenu
-        self.state['yInverted'] = invertY
+        self.state["enableMenu"] = enableMenu
+        self.state["yInverted"] = invertY
 
     def mouseDoubleClickEvent(self, ev):
         if self.parent.loaded:
@@ -49,12 +53,12 @@ def mouseClickEvent(self, ev):
             pos = self.mapSceneToView(ev.scenePos())
             posy = int(pos.x())
             posx = int(pos.y())
-            if self.name=="plot1":
+            if self.name == "plot1":
                 iplot = 0
             else:
                 iplot = 1
-            if posy>=0 and posx>=0 and posy<=self.parent.Lx and posx<=self.parent.Ly:
-                ichosen = int(self.parent.rois['iROI'][iplot, 0, posx, posy])
+            if posy >= 0 and posx >= 0 and posy <= self.parent.Lx and posx <= self.parent.Ly:
+                ichosen = int(self.parent.rois["iROI"][iplot, 0, posx, posy])
                 if ichosen < 0:
                     if ev.button() == QtCore.Qt.RightButton and self.menuEnabled():
                         self.raiseContextMenu(ev)
@@ -67,13 +71,16 @@ def mouseClickEvent(self, ev):
                         masks.flip_plot(self.parent)
                     else:
                         merged = False
-                        if ev.modifiers() == QtCore.Qt.ShiftModifier or ev.modifiers() == QtCore.Qt.ControlModifier:
-                            if self.parent.iscell[self.parent.imerge[0]] == self.parent.iscell[ichosen]:
+                        if ev.modifiers() == QtCore.Qt.ShiftModifier or ev.modifiers(
+                        ) == QtCore.Qt.ControlModifier:
+                            if self.parent.iscell[self.parent.imerge[
+                                    0]] == self.parent.iscell[ichosen]:
                                 if ichosen not in self.parent.imerge:
                                     self.parent.imerge.append(ichosen)
                                     self.parent.ichosen = ichosen
                                     merged = True
-                                elif ichosen in self.parent.imerge and len(self.parent.imerge) > 1:
+                                elif ichosen in self.parent.imerge and len(
+                                        self.parent.imerge) > 1:
                                     self.parent.imerge.remove(ichosen)
                                     self.parent.ichosen = self.parent.imerge[0]
                                     merged = True
@@ -89,46 +96,6 @@ def mouseClickEvent(self, ev):
                                 btn.setStyleSheet(self.parent.styleUnpressed)
                     self.parent.update_plot()
 
-    def mouseDragEvent(self, ev, axis=None):
-        ## if axis is specified, event will only affect that axis.
-        ev.accept()  ## we accept all buttons
-
-        pos = ev.pos()
-        lastPos = ev.lastPos()
-        dif = pos - lastPos
-        dif = dif * -1
-
-        ## Ignore axes if mouse is disabled
-        mouseEnabled = np.array(self.state['mouseEnabled'], dtype=np.float)
-        mask = mouseEnabled.copy()
-        if axis is not None:
-            mask[1-axis] = 0.0
-
-        ## Scale or translate based on mouse button
-        if ev.button() & (QtCore.Qt.LeftButton | QtCore.Qt.MidButton):
-            if self.state['mouseMode'] == pg.ViewBox.RectMode:
-                if ev.isFinish():  ## This is the final move in the drag; change the view scale now
-                    #print "finish"
-                    self.rbScaleBox.hide()
-                    ax = QtCore.QRectF(Point(ev.buttonDownPos(ev.button())), Point(pos))
-                    ax = self.childGroup.mapRectFromParent(ax)
-                    self.showAxRect(ax)
-                    self.axHistoryPointer += 1
-                    self.axHistory = self.axHistory[:self.axHistoryPointer] + [ax]
-                else:
-                    ## update shape of scale box
-                    self.updateScaleBox(ev.buttonDownPos(), ev.pos())
-            else:
-                tr = dif*mask
-                tr = self.mapToView(tr) - self.mapToView(Point(0,0))
-                x = tr.x() if mask[0] == 1 else None
-                y = tr.y() if mask[1] == 1 else None
-
-                self._resetTarget()
-                if x is not None or y is not None:
-                    self.translateBy(x=x, y=y)
-                self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
-
     def zoom_plot(self):
         self.setXRange(0, self.parent.ops["Lx"])
         self.setYRange(0, self.parent.ops["Ly"])
@@ -136,24 +103,25 @@ def zoom_plot(self):
         self.parent.p2.setYLink(self.parent.p1)
         self.parent.show()
 
+
 def init_range(parent):
-    parent.p1.setXRange(0,parent.ops['Lx'])
-    parent.p1.setYRange(0,parent.ops['Ly'])
-    parent.p2.setXRange(0,parent.ops['Lx'])
-    parent.p2.setYRange(0,parent.ops['Ly'])
-    parent.p3.setLimits(xMin=0,xMax=parent.Fcell.shape[1])
+    parent.p1.setXRange(0, parent.ops["Lx"])
+    parent.p1.setYRange(0, parent.ops["Ly"])
+    parent.p2.setXRange(0, parent.ops["Lx"])
+    parent.p2.setYRange(0, parent.ops["Ly"])
+    parent.p3.setLimits(xMin=0, xMax=parent.Fcell.shape[1])
     parent.trange = np.arange(0, parent.Fcell.shape[1])
 
 
 def ROI_index(ops, stat):
-    '''matrix Ly x Lx where each pixel is an ROI index (-1 if no ROI present)'''
-    ncells = len(stat)-1
-    Ly = ops['Ly']
-    Lx = ops['Lx']
-    iROI = -1 * np.ones((Ly,Lx), dtype=np.int32)
+    """matrix Ly x Lx where each pixel is an ROI index (-1 if no ROI present)"""
+    ncells = len(stat) - 1
+    Ly = ops["Ly"]
+    Lx = ops["Lx"]
+    iROI = -1 * np.ones((Ly, Lx), dtype=np.int32)
     for n in range(ncells):
-        ypix = stat[n]['ypix'][~stat[n]['overlap']]
+        ypix = stat[n]["ypix"][~stat[n]["overlap"]]
         if ypix is not None:
-            xpix = stat[n]['xpix'][~stat[n]['overlap']]
-            iROI[ypix,xpix] = n
+            xpix = stat[n]["xpix"][~stat[n]["overlap"]]
+            iROI[ypix, xpix] = n
     return iROI
diff --git a/suite2p/gui/gui2p.py b/suite2p/gui/gui2p.py
index 675a68184..537a45636 100644
--- a/suite2p/gui/gui2p.py
+++ b/suite2p/gui/gui2p.py
@@ -10,6 +10,7 @@
 
 
 class MainWindow(QMainWindow):
+
     def __init__(self, statfile=None):
         super(MainWindow, self).__init__()
         pg.setConfigOptions(imageAxisOrder="row-major")
@@ -18,7 +19,7 @@ def __init__(self, statfile=None):
         self.setWindowTitle("suite2p (run pipeline or load stat.npy)")
         import suite2p
         s2p_dir = pathlib.Path(suite2p.__file__).parent
-        icon_path = os.fspath(s2p_dir.joinpath('logo', 'logo.png'))
+        icon_path = os.fspath(s2p_dir.joinpath("logo", "logo.png"))
 
         app_icon = QtGui.QIcon()
         app_icon.addFile(icon_path, QtCore.QSize(16, 16))
@@ -40,24 +41,24 @@ def __init__(self, statfile=None):
                               "color:gray;}")
         self.loaded = False
         self.ops_plot = []
-        
+
         ### first time running, need to check for user files
-        user_dir = pathlib.Path.home().joinpath('.suite2p')
+        user_dir = pathlib.Path.home().joinpath(".suite2p")
         user_dir.mkdir(exist_ok=True)
 
         # check for classifier file
-        class_dir = user_dir.joinpath('classifiers')
+        class_dir = user_dir.joinpath("classifiers")
         class_dir.mkdir(exist_ok=True)
-        self.classuser = os.fspath(class_dir.joinpath('classifier_user.npy'))
-        self.classorig = os.fspath(s2p_dir.joinpath('classifiers', 'classifier.npy'))
+        self.classuser = os.fspath(class_dir.joinpath("classifier_user.npy"))
+        self.classorig = os.fspath(s2p_dir.joinpath("classifiers", "classifier.npy"))
         if not os.path.isfile(self.classuser):
             shutil.copy(self.classorig, self.classuser)
         self.classfile = self.classuser
 
         # check for ops file (for running suite2p)
-        ops_dir = user_dir.joinpath('ops')
+        ops_dir = user_dir.joinpath("ops")
         ops_dir.mkdir(exist_ok=True)
-        self.opsuser = os.fspath(ops_dir.joinpath('ops_user.npy'))
+        self.opsuser = os.fspath(ops_dir.joinpath("ops_user.npy"))
         if not os.path.isfile(self.opsuser):
             np.save(self.opsuser, default_ops())
         self.opsfile = self.opsuser
@@ -72,11 +73,16 @@ def __init__(self, statfile=None):
         self.boldfont = QtGui.QFont("Arial", 10, QtGui.QFont.Bold)
 
         # default plot options
-        self.ops_plot = {'ROIs_on': True, 'color': 0, 'view': 0,
-                         'opacity': [127,255], 'saturation': [0, 255],
-                         'colormap': 'hsv'}
-        self.rois = {'iROI':0, 'Sroi':0, 'Lam':0, 'LamMean':0, 'LamNorm':0}
-        self.colors = {'RGB':0, 'cols':0, 'colorbar':[]}
+        self.ops_plot = {
+            "ROIs_on": True,
+            "color": 0,
+            "view": 0,
+            "opacity": [127, 255],
+            "saturation": [0, 255],
+            "colormap": "hsv"
+        }
+        self.rois = {"iROI": 0, "Sroi": 0, "Lam": 0, "LamMean": 0, "LamNorm": 0}
+        self.colors = {"RGB": 0, "cols": 0, "colorbar": []}
 
         # --------- MAIN WIDGET LAYOUT ---------------------
         cwidget = QWidget()
@@ -86,7 +92,7 @@ def __init__(self, statfile=None):
 
         b0 = self.make_buttons()
         self.make_graphics(b0)
-        # so they're on top of plot, draw last
+        # so they"re on top of plot, draw last
         buttons.make_quadrants(self)
 
         # initialize merges
@@ -98,10 +104,10 @@ def __init__(self, statfile=None):
         self.default_keys = model["keys"]
 
         # load initial file
-        #statfile = 'C:/Users/carse/OneDrive/Documents/suite2p/plane0/stat.npy'
-        #statfile = 'D:/grive/cshl_suite2p/GT1/suite2p/plane0/stat.npy'
-        #statfile = '/media/carsen/DATA1/TIFFS/auditory_cortex/suite2p/plane0/stat.npy'
-        #folder = 'D:/DATA/GT1/singlechannel_half/suite2p/'
+        #statfile = "C:/Users/carse/OneDrive/Documents/suite2p/plane0/stat.npy"
+        #statfile = "D:/grive/cshl_suite2p/GT1/suite2p/plane0/stat.npy"
+        #statfile = "/media/carsen/DATA1/TIFFS/auditory_cortex/suite2p/plane0/stat.npy"
+        #folder = "D:/DATA/GT1/singlechannel_half/suite2p/"
         #self.fname = folder
         #io.load_folder(self)
         if statfile is not None:
@@ -122,13 +128,13 @@ def dropEvent(self, event):
         files = [u.toLocalFile() for u in event.mimeData().urls()]
         print(files)
         self.fname = files[0]
-        if os.path.splitext(self.fname)[-1]=='.npy':
+        if os.path.splitext(self.fname)[-1] == ".npy":
             io.load_proc(self)
-        elif os.path.splitext(self.fname)[-1]=='.nwb':
+        elif os.path.splitext(self.fname)[-1] == ".nwb":
             io.load_NWB(self)
         else:
-            print('invalid extension %s, use .nwb or .npy'%os.path.splitext(self.fname)[-1])
-
+            print("invalid extension %s, use .nwb or .npy" %
+                  os.path.splitext(self.fname)[-1])
 
     def make_buttons(self):
         # ROI CHECKBOX
@@ -141,22 +147,17 @@ def make_buttons(self):
 
         buttons.make_selection(self)
         buttons.make_cellnotcell(self)
-        b0=views.make_buttons(self) # b0 says how many
-        b0=masks.make_buttons(self,b0)
+        b0 = views.make_buttons(self)  # b0 says how many
+        b0 = masks.make_buttons(self, b0)
         masks.make_colorbar(self, b0)
-        b0+=1
-        b0=classgui.make_buttons(self, b0)
-        b0+=1
+        b0 += 1
+        b0 = classgui.make_buttons(self, b0)
+        b0 += 1
 
         # ------ CELL STATS / ROI SELECTION --------
         # which stats
         self.stats_to_show = [
-            "med",
-            "npix",
-            "skew",
-            "compact",
-            "footprint",
-            "aspect_ratio"
+            "med", "npix", "skew", "compact", "footprint", "aspect_ratio"
         ]
         lilfont = QtGui.QFont("Arial", 8)
         qlabel = QLabel(self)
@@ -170,7 +171,7 @@ def make_buttons(self):
         self.ROIedit.setAlignment(QtCore.Qt.AlignRight)
         self.ROIedit.returnPressed.connect(self.number_chosen)
         self.l0.addWidget(self.ROIedit, b0, 1, 1, 1)
-        b0+=1
+        b0 += 1
         self.ROIstats = []
         self.ROIstats.append(qlabel)
         for k in range(1, len(self.stats_to_show) + 1):
@@ -180,10 +181,10 @@ def make_buttons(self):
             self.ROIstats[k].setStyleSheet("color: white;")
             self.ROIstats[k].resize(self.ROIstats[k].minimumSizeHint())
             self.l0.addWidget(self.ROIstats[k], b0, 0, 1, 2)
-            b0+=1
-        self.l0.addWidget(QLabel(""), b0 , 0, 1, 2)
+            b0 += 1
+        self.l0.addWidget(QLabel(""), b0, 0, 1, 2)
         self.l0.setRowStretch(b0, 1)
-        b0+=2
+        b0 += 2
         b0 = traces.make_buttons(self, b0)
 
         # zoom to cell CHECKBOX
@@ -192,32 +193,28 @@ def make_buttons(self):
         self.checkBoxz.setStyleSheet("color: white;")
         self.zoomtocell = False
         self.checkBoxz.stateChanged.connect(self.zoom_cell)
-        self.l0.addWidget(self.checkBoxz,
-        b0,15,
-        1, 2)
+        self.l0.addWidget(self.checkBoxz, b0, 15, 1, 2)
 
         self.checkBoxN = QCheckBox("add ROI # to plot")
         self.checkBoxN.setStyleSheet("color: white;")
         self.roitext = False
         self.checkBoxN.stateChanged.connect(self.roi_text)
         self.checkBoxN.setEnabled(False)
-        self.l0.addWidget(self.checkBoxN,
-        b0,18,
-        1, 2)
-        
+        self.l0.addWidget(self.checkBoxN, b0, 18, 1, 2)
+
         return b0
 
     def roi_text(self, state):
         if state == QtCore.Qt.Checked:
             for n in range(len(self.roi_text_labels)):
-                if self.iscell[n]==1:
+                if self.iscell[n] == 1:
                     self.p1.addItem(self.roi_text_labels[n])
                 else:
                     self.p2.addItem(self.roi_text_labels[n])
             self.roitext = True
         else:
             for n in range(len(self.roi_text_labels)):
-                if self.iscell[n]==1:
+                if self.iscell[n] == 1:
                     try:
                         self.p1.removeItem(self.roi_text_labels[n])
                     except:
@@ -243,10 +240,11 @@ def make_graphics(self, b0):
         self.win = pg.GraphicsLayoutWidget()
         self.win.move(600, 0)
         self.win.resize(1000, 500)
-        self.l0.addWidget(self.win, 1, 2, b0-1, 30)
+        self.l0.addWidget(self.win, 1, 2, b0 - 1, 30)
         layout = self.win.ci.layout
         # --- cells image
-        self.p1 = graphics.ViewBox(parent=self, lockAspect=True, name="plot1", border=[100, 100, 100], invertY=True)
+        self.p1 = graphics.ViewBox(parent=self, lockAspect=True, name="plot1",
+                                   border=[100, 100, 100], invertY=True)
         self.win.addItem(self.p1, 0, 0)
         self.p1.setMenuEnabled(False)
         self.p1.scene().contextMenuItem = self.p1
@@ -256,14 +254,15 @@ def make_graphics(self, b0):
         self.color1.autoDownsample = False
         self.p1.addItem(self.view1)
         self.p1.addItem(self.color1)
-        self.view1.setLevels([0,255])
-        self.color1.setLevels([0,255])
+        self.view1.setLevels([0, 255])
+        self.color1.setLevels([0, 255])
         #self.view1.setImage(np.random.rand(500,500,3))
         #x = np.arange(0,500)
         #img = np.concatenate((np.zeros((500,500,3)), 127*(1+np.tile(np.sin(x/100)[:,np.newaxis,np.newaxis],(1,500,1)))),axis=-1)
         #self.color1.setImage(img)
         # --- noncells image
-        self.p2 = graphics.ViewBox(parent=self, lockAspect=True, name="plot2", border=[100, 100, 100], invertY=True)
+        self.p2 = graphics.ViewBox(parent=self, lockAspect=True, name="plot2",
+                                   border=[100, 100, 100], invertY=True)
         self.win.addItem(self.p2, 0, 1)
         self.p2.setMenuEnabled(False)
         self.p2.scene().contextMenuItem = self.p2
@@ -273,8 +272,8 @@ def make_graphics(self, b0):
         self.color2.autoDownsample = False
         self.p2.addItem(self.view2)
         self.p2.addItem(self.color2)
-        self.view2.setLevels([0,255])
-        self.color2.setLevels([0,255])
+        self.view2.setLevels([0, 255])
+        self.color2.setLevels([0, 255])
 
         # LINK TWO VIEWS!
         self.p2.setXLink("plot1")
@@ -296,9 +295,10 @@ def make_graphics(self, b0):
 
     def keyPressEvent(self, event):
         if self.loaded:
-            if event.modifiers() != QtCore.Qt.ControlModifier and event.modifiers() != QtCore.Qt.ShiftModifier:
+            if event.modifiers() != QtCore.Qt.ControlModifier and event.modifiers(
+            ) != QtCore.Qt.ShiftModifier:
                 if event.key() == QtCore.Qt.Key_Return:
-                    if event.modifiers()==QtCore.Qt.AltModifier:
+                    if event.modifiers() == QtCore.Qt.AltModifier:
                         if len(self.imerge) > 1:
                             merge.do_merge(self)
                 elif event.key() == QtCore.Qt.Key_Escape:
@@ -376,7 +376,7 @@ def keyPressEvent(self, event):
                 elif event.key() == QtCore.Qt.Key_Left:
                     ctype = self.iscell[self.ichosen]
                     while -1:
-                        self.ichosen = (self.ichosen-1)%len(self.stat)
+                        self.ichosen = (self.ichosen - 1) % len(self.stat)
                         if self.iscell[self.ichosen] is ctype:
                             break
                     self.imerge = [self.ichosen]
@@ -384,11 +384,11 @@ def keyPressEvent(self, event):
                     self.update_plot()
 
                 elif event.key() == QtCore.Qt.Key_Right:
-                ##Agus
+                    ##Agus
                     self.ROI_remove()
                     ctype = self.iscell[self.ichosen]
                     while 1:
-                        self.ichosen = (self.ichosen+1)%len(self.stat)
+                        self.ichosen = (self.ichosen + 1) % len(self.stat)
                         if self.iscell[self.ichosen] is ctype:
                             break
                     self.imerge = [self.ichosen]
@@ -399,9 +399,8 @@ def keyPressEvent(self, event):
                     masks.flip_plot(self)
                     self.ROI_remove()
 
-
     def update_plot(self):
-        if self.ops_plot['color'] == 7:
+        if self.ops_plot["color"] == 7:
             masks.corr_masks(self)
         masks.plot_colorbar(self)
         self.ichosen_stats()
@@ -445,15 +444,14 @@ def mode_change(self, i):
             else:
                 f = self.Spks
             ncells = len(self.stat)
-            self.Fbin = f[:, : nb * self.bin].reshape(
-                (ncells, nb, self.bin)
-            ).mean(axis=2)
+            self.Fbin = f[:, :nb * self.bin].reshape(
+                (ncells, nb, self.bin)).mean(axis=2)
 
             self.Fbin -= self.Fbin.mean(axis=1)[:, np.newaxis]
-            self.Fstd = (self.Fbin ** 2).mean(axis=1)**0.5
+            self.Fstd = (self.Fbin**2).mean(axis=1)**0.5
             self.trange = np.arange(0, self.Fcell.shape[1])
             # if in behavior-view, recompute
-            if self.ops_plot['color'] == 8:
+            if self.ops_plot["color"] == 8:
                 masks.beh_masks(self)
                 masks.plot_colorbar(self)
             self.update_plot()
@@ -489,10 +487,7 @@ def ROI_selection(self):
             dy = np.minimum(dy, 300)
             imx = imx - dx / 2
             imy = imy - dy / 2
-            self.ROI = pg.RectROI(
-                [imx, imy], [dx, dy],
-                pen="w", sideScalers=True
-            )
+            self.ROI = pg.RectROI([imx, imy], [dx, dy], pen="w", sideScalers=True)
             if wplot == 0:
                 self.p1.addItem(self.ROI)
             else:
@@ -534,11 +529,12 @@ def ROI_position(self):
 
     def select_cells(self, ypix, xpix):
         i = self.ROIplot
-        iROI0 = self.rois['iROI'][i, 0, ypix, xpix]
+        iROI0 = self.rois["iROI"][i, 0, ypix, xpix]
         icells = np.unique(iROI0[iROI0 >= 0])
         self.imerge = []
         for n in icells:
-            if (self.rois['iROI'][i, :, ypix, xpix] == n).sum() > 0.6 * self.stat[n]["npix"]:
+            if (self.rois["iROI"][i, :, ypix,
+                                  xpix] == n).sum() > 0.6 * self.stat[n]["npix"]:
                 self.imerge.append(n)
         if len(self.imerge) > 0:
             self.ichosen = self.imerge[0]
@@ -554,15 +550,13 @@ def number_chosen(self):
             self.update_plot()
             self.show()
 
-
-
     def ROIs_on(self, state):
         if state == QtCore.Qt.Checked:
-            self.ops_plot['ROIs_on'] = True
+            self.ops_plot["ROIs_on"] = True
             self.p1.addItem(self.color1)
             self.p2.addItem(self.color2)
         else:
-            self.ops_plot['ROIs_on'] = False
+            self.ops_plot["ROIs_on"] = False
             self.p1.removeItem(self.color1)
             self.p2.removeItem(self.color2)
         self.win.show()
@@ -593,11 +587,8 @@ def plot_clicked(self, event):
                     iplot = 2
                 elif x == self.p3:
                     iplot = 3
-                elif (
-                    (x == self.p1 or x == self.p2) and
-                    x != self.img1 and
-                    x != self.img2
-                ):
+                elif ((x == self.p1 or x == self.p2) and x != self.img1 and
+                      x != self.img2):
                     iplot = 4
                     if event.double():
                         zoom = True
@@ -622,7 +613,8 @@ def plot_clicked(self, event):
                         flip = False
                 if choose:
                     merged = False
-                    if event.modifiers() == QtCore.Qt.ShiftModifier or event.modifiers() == QtCore.Qt.ControlModifier:
+                    if event.modifiers() == QtCore.Qt.ShiftModifier or event.modifiers(
+                    ) == QtCore.Qt.ControlModifier:
                         if self.iscell[self.imerge[0]] == self.iscell[ichosen]:
                             if ichosen not in self.imerge:
                                 self.imerge.append(ichosen)
@@ -663,9 +655,7 @@ def ichosen_stats(self):
             key = self.stats_to_show[k - 1]
             ival = self.stat[n][key]
             if k == 1:
-                self.ROIstats[k].setText(
-                    key + ": [%d, %d]" % (ival[0], ival[1])
-                )
+                self.ROIstats[k].setText(key + ": [%d, %d]" % (ival[0], ival[1]))
             elif k == 2:
                 self.ROIstats[k].setText(key + ": %d" % (ival))
             else:
@@ -674,22 +664,23 @@ def ichosen_stats(self):
     def zoom_to_cell(self):
         irange = 0.1 * np.array([self.Ly, self.Lx]).max()
         if len(self.imerge) > 1:
-            apix = np.zeros((0,2))
-            for i,k in enumerate(self.imerge):
-                apix = np.append(apix,
-                        np.concatenate((self.stat[k]['ypix'].flatten()[:,np.newaxis],
-                                        self.stat[k]['xpix'].flatten()[:,np.newaxis]), axis=1),
-                        axis=0)
+            apix = np.zeros((0, 2))
+            for i, k in enumerate(self.imerge):
+                apix = np.append(
+                    apix,
+                    np.concatenate((self.stat[k]["ypix"].flatten()[:, np.newaxis],
+                                    self.stat[k]["xpix"].flatten()[:, np.newaxis]),
+                                   axis=1), axis=0)
 
             imin = apix.min(axis=0)
             imax = apix.max(axis=0)
             icent = apix.mean(axis=0)
-            imin[0] = min(icent[0]-irange, imin[0])
-            imin[1] = min(icent[1]-irange, imin[1])
-            imax[0] = max(icent[0]+irange, imax[0])
-            imax[1] = max(icent[1]+irange, imax[1])
+            imin[0] = min(icent[0] - irange, imin[0])
+            imin[1] = min(icent[1] - irange, imin[1])
+            imax[0] = max(icent[0] + irange, imax[0])
+            imax[1] = max(icent[1] + irange, imax[1])
         else:
-            icent = np.array(self.stat[self.ichosen]['med'])
+            icent = np.array(self.stat[self.ichosen]["med"])
             imin = icent - irange
             imax = icent + irange
         self.p1.setYRange(imin[0], imax[0])
@@ -699,14 +690,14 @@ def zoom_to_cell(self):
         self.win.show()
         self.show()
 
+
 def run(statfile=None):
     # Always start by initializing Qt (only once per application)
     warnings.filterwarnings("ignore")
     app = QApplication(sys.argv)
     import suite2p
     s2ppath = os.path.dirname(os.path.realpath(suite2p.__file__))
-    icon_path = os.path.join(s2ppath, "logo","logo.png"
-    )
+    icon_path = os.path.join(s2ppath, "logo", "logo.png")
     app_icon = QtGui.QIcon()
     app_icon.addFile(icon_path, QtCore.QSize(16, 16))
     app_icon.addFile(icon_path, QtCore.QSize(24, 24))
diff --git a/suite2p/gui/io.py b/suite2p/gui/io.py
index b2d8cb1e7..1ecd231d5 100644
--- a/suite2p/gui/io.py
+++ b/suite2p/gui/io.py
@@ -12,16 +12,17 @@ def export_fig(parent):
     parent.win.scene().contextMenuItem = parent.p1
     parent.win.scene().showExportDialog()
 
+
 def make_masks_and_enable_buttons(parent):
     parent.checkBox.setChecked(True)
-    parent.ops_plot['color'] = 0
-    parent.ops_plot['view'] = 0
-    parent.colors['cols'] = 0
-    parent.colors['istat'] = 0
+    parent.ops_plot["color"] = 0
+    parent.ops_plot["view"] = 0
+    parent.colors["cols"] = 0
+    parent.colors["istat"] = 0
     if parent.checkBoxN.isChecked():
         parent.roi_text(False)
-    parent.roi_text_labels=[]
-    parent.roitext = False 
+    parent.roi_text_labels = []
+    parent.roitext = False
     parent.checkBoxN.setChecked(False)
     parent.checkBoxN.setEnabled(True)
     parent.loadBeh.setEnabled(True)
@@ -49,16 +50,9 @@ def make_masks_and_enable_buttons(parent):
         yext, xext = utils.boundary(ypix, xpix)
         parent.stat[n]["yext"] = yext
         parent.stat[n]["xext"] = xext
-        ycirc, xcirc = utils.circle(
-            parent.stat[n]["med"],
-            parent.stat[n]["radius"]
-        )
-        goodi = (
-            (ycirc >= 0)
-            & (xcirc >= 0)
-            & (ycirc < parent.ops["Ly"])
-            & (xcirc < parent.ops["Lx"])
-        )
+        ycirc, xcirc = utils.circle(parent.stat[n]["med"], parent.stat[n]["radius"])
+        goodi = ((ycirc >= 0) & (xcirc >= 0) & (ycirc < parent.ops["Ly"]) &
+                 (xcirc < parent.ops["Lx"]))
         parent.stat[n]["ycirc"] = ycirc[goodi]
         parent.stat[n]["xcirc"] = xcirc[goodi]
         parent.stat[n]["inmerge"] = 0
@@ -68,7 +62,7 @@ def make_masks_and_enable_buttons(parent):
     views.init_views(parent)
     # make color arrays for various views
     masks.make_colors(parent)
-    
+
     if parent.iscell.sum() > 0:
         ich = np.nonzero(parent.iscell)[0][0]
     else:
@@ -85,18 +79,17 @@ def make_masks_and_enable_buttons(parent):
     masks.init_masks(parent)
     M = masks.draw_masks(parent)
     masks.plot_masks(parent, M)
-    print(f'time to draw and plot masks: {time.time() - tic : .4f} sec')
+    print(f"time to draw and plot masks: {time.time() - tic : .4f} sec")
     parent.lcell1.setText("%d" % (ncells - parent.iscell.sum()))
     parent.lcell0.setText("%d" % (parent.iscell.sum()))
     graphics.init_range(parent)
     traces.plot_trace(parent)
     parent.xyrat = 1.0
-    if (isinstance(parent.ops['diameter'], (list, np.ndarray)) and
-        len(parent.ops['diameter'])>1 and
-        parent.ops.get('aspect', 1.0)):
+    if (isinstance(parent.ops["diameter"], (list, np.ndarray)) and
+            len(parent.ops["diameter"]) > 1 and parent.ops.get("aspect", 1.0)):
         parent.xyrat = parent.ops["diameter"][0] / parent.ops["diameter"][1]
     else:
-        parent.xyrat = parent.ops.get('aspect', 1.0)
+        parent.xyrat = parent.ops.get("aspect", 1.0)
 
     parent.p1.setAspectLocked(lock=True, ratio=parent.xyrat)
     parent.p2.setAspectLocked(lock=True, ratio=parent.xyrat)
@@ -108,6 +101,7 @@ def make_masks_and_enable_buttons(parent):
     # no classifier loaded
     classgui.activate(parent, False)
 
+
 def enable_views_and_classifier(parent):
     for b in range(9):
         parent.quadbtns.button(b).setEnabled(True)
@@ -115,7 +109,7 @@ def enable_views_and_classifier(parent):
     for b in range(len(parent.view_names)):
         parent.viewbtns.button(b).setEnabled(True)
         parent.viewbtns.button(b).setStyleSheet(parent.styleUnpressed)
-        # parent.viewbtns.button(b).setShortcut(QtGui.QKeySequence('R'))
+        # parent.viewbtns.button(b).setShortcut(QtGui.QKeySequence("R"))
         if b == 0:
             parent.viewbtns.button(b).setChecked(True)
             parent.viewbtns.button(b).setStyleSheet(parent.stylePressed)
@@ -128,15 +122,15 @@ def enable_views_and_classifier(parent):
             parent.viewbtns.button(6).setStyleSheet(parent.styleInactive)
 
     for b in range(len(parent.color_names)):
-        if b==5:
+        if b == 5:
             if parent.hasred:
                 parent.colorbtns.button(b).setEnabled(True)
                 parent.colorbtns.button(b).setStyleSheet(parent.styleUnpressed)
-        elif b==0:
+        elif b == 0:
             parent.colorbtns.button(b).setEnabled(True)
             parent.colorbtns.button(b).setChecked(True)
             parent.colorbtns.button(b).setStyleSheet(parent.stylePressed)
-        elif b<8:
+        elif b < 8:
             parent.colorbtns.button(b).setEnabled(True)
             parent.colorbtns.button(b).setStyleSheet(parent.styleUnpressed)
 
@@ -152,7 +146,7 @@ def enable_views_and_classifier(parent):
             btn.press(parent)
         b += 1
     for b in range(3):
-        if b==0:
+        if b == 0:
             parent.topbtns.button(b).setEnabled(True)
             parent.topbtns.button(b).setStyleSheet(parent.styleUnpressed)
         else:
@@ -168,79 +162,81 @@ def enable_views_and_classifier(parent):
     parent.custommask.setEnabled(True)
     # parent.p1.scene().showExportDialog()
 
+
 def load_dialog(parent):
     options = QFileDialog.Options()
     options |= QFileDialog.DontUseNativeDialog
-    name = QFileDialog.getOpenFileName(
-        parent, "Open stat.npy", filter="stat.npy",
-        options=options
-    )
+    name = QFileDialog.getOpenFileName(parent, "Open stat.npy", filter="stat.npy",
+                                       options=options)
     parent.fname = name[0]
     load_proc(parent)
 
+
 def load_dialog_NWB(parent):
-    options=QFileDialog.Options()
+    options = QFileDialog.Options()
     options |= QFileDialog.DontUseNativeDialog
-    name = QFileDialog.getOpenFileName(
-        parent, "Open ophys.nwb", filter="*.nwb",
-        options=options
-    )
+    name = QFileDialog.getOpenFileName(parent, "Open ophys.nwb", filter="*.nwb",
+                                       options=options)
     parent.fname = name[0]
     load_NWB(parent)
-    
+
+
 def load_dialog_folder(parent):
-    options=QFileDialog.Options()
+    options = QFileDialog.Options()
     options |= QFileDialog.DontUseNativeDialog
-    name = QFileDialog.getExistingDirectory(
-        parent, "Open folder with planeX folders",
-        options=options
-    )
+    name = QFileDialog.getExistingDirectory(parent, "Open folder with planeX folders",
+                                            options=options)
     parent.fname = name
     load_folder(parent)
 
+
 def load_NWB(parent):
     name = parent.fname
     print(name)
     try:
         procs = list(io.read_nwb(name))
-        if procs[1]['nchannels']==2:
+        if procs[1]["nchannels"] == 2:
             hasred = True
         else:
             hasred = False
         procs.append(hasred)
         load_to_GUI(parent, os.path.split(name)[0], procs)
-            
+
         parent.loaded = True
     except Exception as e:
-        print('ERROR with NWB: %s'%e)
+        print("ERROR with NWB: %s" % e)
+
 
 def load_folder(parent):
     print(parent.fname)
     save_folder = parent.fname
-    plane_folders = [ f.path for f in os.scandir(save_folder) if f.is_dir() and f.name[:5]=='plane']
+    plane_folders = [
+        f.path for f in os.scandir(save_folder) if f.is_dir() and f.name[:5] == "plane"
+    ]
     stat_found = False
     if len(plane_folders) > 0:
-        stat_found = all([os.path.isfile(os.path.join(f, 'stat.npy')) for f in plane_folders])
+        stat_found = all(
+            [os.path.isfile(os.path.join(f, "stat.npy")) for f in plane_folders])
     if not stat_found:
-        print('No processed planeX folders in folder')
+        print("No processed planeX folders in folder")
         return
 
     # create a combined folder to hold iscell and redcell
     output = io.combined(save_folder, save=False)
-    parent.basename = os.path.join(parent.fname, 'combined')
+    parent.basename = os.path.join(parent.fname, "combined")
     load_to_GUI(parent, parent.basename, output)
     parent.loaded = True
     print(parent.fname)
 
+
 def load_files(name):
     """ give stat.npy path and load all needed files for suite2p """
     try:
         stat = np.load(name, allow_pickle=True)
         ypix = stat[0]["ypix"]
-    except (ValueError, KeyError, OSError,
-            RuntimeError, TypeError, NameError):
-        print('ERROR: this is not a stat.npy file :( '
-              '(needs stat[n]["ypix"]!)')
+    except (ValueError, KeyError, OSError, RuntimeError, TypeError, NameError):
+        print("ERROR: this is not a stat.npy file :( "
+              "(needs stat[n]['ypix']!)")
         stat = None
     goodfolder = False
     if stat is not None:
@@ -250,10 +246,8 @@ def load_files(name):
             Fcell = np.load(basename + "/F.npy")
             Fneu = np.load(basename + "/Fneu.npy")
         except (ValueError, OSError, RuntimeError, TypeError, NameError):
-            print(
-                "ERROR: there are no fluorescence traces in this folder "
-                "(F.npy/Fneu.npy)"
-            )
+            print("ERROR: there are no fluorescence traces in this folder "
+                  "(F.npy/Fneu.npy)")
             goodfolder = False
         try:
             Spks = np.load(basename + "/spks.npy")
@@ -269,24 +263,24 @@ def load_files(name):
         try:
             iscell = np.load(basename + "/iscell.npy")
             probcell = iscell[:, 1]
-            iscell = iscell[:, 0].astype('bool')
+            iscell = iscell[:, 0].astype("bool")
         except (ValueError, OSError, RuntimeError, TypeError, NameError):
             print("no manual labels found (iscell.npy)")
             if goodfolder:
                 NN = Fcell.shape[0]
-                iscell = np.ones((NN,), 'bool')
+                iscell = np.ones((NN,), "bool")
                 probcell = np.ones((NN,), np.float32)
         try:
             redcell = np.load(basename + "/redcell.npy")
-            probredcell = redcell[:,1].copy()
-            redcell = redcell[:,0].astype('bool')
+            probredcell = redcell[:, 1].copy()
+            redcell = redcell[:, 0].astype("bool")
             hasred = True
         except (ValueError, OSError, RuntimeError, TypeError, NameError):
             print("no channel 2 labels found (redcell.npy)")
             hasred = False
             if goodfolder:
                 NN = Fcell.shape[0]
-                redcell = np.zeros((NN,), 'bool')
+                redcell = np.zeros((NN,), "bool")
                 probredcell = np.zeros((NN,), np.float32)
     else:
         print("incorrect file, not a stat.npy")
@@ -298,6 +292,7 @@ def load_files(name):
         print("stat.npy found, but other files not in folder")
         return None
 
+
 def load_proc(parent):
     name = parent.fname
     print(name)
@@ -310,6 +305,7 @@ def load_proc(parent):
         Text = "Incorrect files, choose another?"
         load_again(parent, Text)
 
+
 def load_to_GUI(parent, basename, procs):
     stat, ops, Fcell, Fneu, Spks, iscell, probcell, redcell, probredcell, hasred = procs
     parent.basename = basename
@@ -318,34 +314,33 @@ def load_to_GUI(parent, basename, procs):
     parent.Fcell = Fcell
     parent.Fneu = Fneu
     parent.Spks = Spks
-    parent.iscell = iscell.astype('bool')
+    parent.iscell = iscell.astype("bool")
     parent.probcell = probcell
-    parent.redcell = redcell.astype('bool')
+    parent.redcell = redcell.astype("bool")
     parent.probredcell = probredcell
     parent.hasred = hasred
-    parent.notmerged = np.ones_like(parent.iscell).astype('bool')
+    parent.notmerged = np.ones_like(parent.iscell).astype("bool")
     for n in range(len(parent.stat)):
         if parent.hasred:
-            parent.stat[n]['chan2_prob'] = parent.probredcell[n]
-        parent.stat[n]['inmerge'] = 0
+            parent.stat[n]["chan2_prob"] = parent.probredcell[n]
+        parent.stat[n]["inmerge"] = 0
     parent.stat = np.array(parent.stat)
     make_masks_and_enable_buttons(parent)
     parent.ichosen = 0
     parent.imerge = [0]
     for n in range(len(parent.stat)):
-        if 'imerge' not in parent.stat[n]:
-            parent.stat[n]['imerge'] = []
+        if "imerge" not in parent.stat[n]:
+            parent.stat[n]["imerge"] = []
+
 
 def load_behavior(parent):
-    name = QFileDialog.getOpenFileName(
-        parent, "Open *.npy", filter="*.npy"
-    )
+    name = QFileDialog.getOpenFileName(parent, "Open *.npy", filter="*.npy")
     name = name[0]
     bloaded = False
     try:
         beh = np.load(name)
-        bresample=False
-        if beh.ndim>1:
+        bresample = False
+        if beh.ndim > 1:
             if beh.shape[1] < 2:
                 beh = beh.flatten()
                 if beh.shape[0] == parent.Fcell.shape[1]:
@@ -353,15 +348,14 @@ def load_behavior(parent):
                     beh_time = np.arange(0, parent.Fcell.shape[1])
             else:
                 parent.bloaded = True
-                beh_time = beh[:,1]
-                beh = beh[:,0]
-                bresample=True
+                beh_time = beh[:, 1]
+                beh = beh[:, 0]
+                bresample = True
         else:
             if beh.shape[0] == parent.Fcell.shape[1]:
                 parent.bloaded = True
                 beh_time = np.arange(0, parent.Fcell.shape[1])
-    except (ValueError, KeyError, OSError,
-            RuntimeError, TypeError, NameError):
+    except (ValueError, KeyError, OSError, RuntimeError, TypeError, NameError):
         print("ERROR: this is not a 1D array with length of data")
     if parent.bloaded:
         beh -= beh.min()
@@ -369,7 +363,8 @@ def load_behavior(parent):
         parent.beh = beh
         parent.beh_time = beh_time
         if bresample:
-            parent.beh_resampled = resample_frames(parent.beh, parent.beh_time, np.arange(0,parent.Fcell.shape[1]))
+            parent.beh_resampled = resample_frames(parent.beh, parent.beh_time,
+                                                   np.arange(0, parent.Fcell.shape[1]))
         else:
             parent.beh_resampled = parent.beh
         b = 8
@@ -377,7 +372,7 @@ def load_behavior(parent):
         parent.colorbtns.button(b).setStyleSheet(parent.styleUnpressed)
         masks.beh_masks(parent)
         traces.plot_trace(parent)
-        if hasattr(parent, 'VW'):
+        if hasattr(parent, "VW"):
             parent.VW.bloaded = parent.bloaded
             parent.VW.beh = parent.beh
             parent.VW.beh_time = parent.beh_time
@@ -386,18 +381,23 @@ def load_behavior(parent):
     else:
         print("ERROR: this is not a 1D array with length of data")
 
+
 def resample_frames(y, x, xt):
-    ''' resample y (defined at x) at times xt '''
+    """ resample y (defined at x) at times xt """
     ts = x.size / xt.size
-    y = gaussian_filter1d(y, np.ceil(ts/2), axis=0)
-    f = interp1d(x,y,fill_value="extrapolate")
+    y = gaussian_filter1d(y, np.ceil(ts / 2), axis=0)
+    f = interp1d(x, y, fill_value="extrapolate")
     yt = f(xt)
     return yt
 
+
 def save_redcell(parent):
-    np.save(os.path.join(parent.basename, 'redcell.npy'),
-            np.concatenate((np.expand_dims(parent.redcell[parent.notmerged],axis=1),
-            np.expand_dims(parent.probredcell[parent.notmerged],axis=1)), axis=1))
+    np.save(
+        os.path.join(parent.basename, "redcell.npy"),
+        np.concatenate((np.expand_dims(parent.redcell[parent.notmerged], axis=1),
+                        np.expand_dims(parent.probredcell[parent.notmerged], axis=1)),
+                       axis=1))
+
 
 def save_iscell(parent):
     np.save(
@@ -413,76 +413,87 @@ def save_iscell(parent):
     parent.lcell0.setText("%d" % (parent.iscell.sum()))
     parent.lcell1.setText("%d" % (parent.iscell.size - parent.iscell.sum()))
 
+
 def save_mat(parent):
-    print('saving to mat')
-    matpath = os.path.join(parent.basename,'Fall.mat')
-    if 'date_proc' in parent.ops:
-        parent.ops['date_proc'] = []
-    scipy.io.savemat(matpath, {'stat': parent.stat,
-                         'ops': parent.ops,
-                         'F': parent.Fcell,
-                         'Fneu': parent.Fneu,
-                         'spks': parent.Spks,
-                         'iscell': np.concatenate((parent.iscell[:,np.newaxis],
-                                                   parent.probcell[:,np.newaxis]), axis=1),
-                         'redcell': np.concatenate((np.expand_dims(parent.redcell,axis=1),
-                         np.expand_dims(parent.probredcell,axis=1)), axis=1)
-                         })
+    print("saving to mat")
+    matpath = os.path.join(parent.basename, "Fall.mat")
+    if "date_proc" in parent.ops:
+        parent.ops["date_proc"] = []
+    scipy.io.savemat(
+        matpath, {
+            "stat":
+                parent.stat,
+            "ops":
+                parent.ops,
+            "F":
+                parent.Fcell,
+            "Fneu":
+                parent.Fneu,
+            "spks":
+                parent.Spks,
+            "iscell":
+                np.concatenate(
+                    (parent.iscell[:, np.newaxis], parent.probcell[:, np.newaxis]),
+                    axis=1),
+            "redcell":
+                np.concatenate((np.expand_dims(parent.redcell, axis=1),
+                                np.expand_dims(parent.probredcell, axis=1)), axis=1)
+        })
+
 
 def save_merge(parent):
-    print('saving to NPY')
-    np.save(os.path.join(parent.basename, 'ops.npy'), parent.ops)
-    np.save(os.path.join(parent.basename, 'stat.npy'), parent.stat)
-    np.save(os.path.join(parent.basename, 'F.npy'), parent.Fcell)
-    np.save(os.path.join(parent.basename, 'Fneu.npy'), parent.Fneu)
+    print("saving to NPY")
+    np.save(os.path.join(parent.basename, "ops.npy"), parent.ops)
+    np.save(os.path.join(parent.basename, "stat.npy"), parent.stat)
+    np.save(os.path.join(parent.basename, "F.npy"), parent.Fcell)
+    np.save(os.path.join(parent.basename, "Fneu.npy"), parent.Fneu)
     if parent.hasred:
-        np.save(os.path.join(parent.basename, 'F_chan2.npy'), parent.F_chan2)
-        np.save(os.path.join(parent.basename, 'Fneu_chan2.npy'), parent.Fneu_chan2)
-        np.save(os.path.join(parent.basename, 'redcell.npy'),
-                np.concatenate((np.expand_dims(parent.redcell,axis=1),
-                np.expand_dims(parent.probredcell,axis=1)), axis=1))
-    np.save(os.path.join(parent.basename, 'spks.npy'), parent.Spks)
-    iscell =  np.concatenate((parent.iscell[:,np.newaxis],
-                              parent.probcell[:,np.newaxis]), axis=1)
-    np.save(os.path.join(parent.basename, 'iscell.npy'), iscell)
-    
-    parent.notmerged = np.ones(parent.iscell.size, 'bool')
+        np.save(os.path.join(parent.basename, "F_chan2.npy"), parent.F_chan2)
+        np.save(os.path.join(parent.basename, "Fneu_chan2.npy"), parent.Fneu_chan2)
+        np.save(
+            os.path.join(parent.basename, "redcell.npy"),
+            np.concatenate((np.expand_dims(
+                parent.redcell, axis=1), np.expand_dims(parent.probredcell, axis=1)),
+                           axis=1))
+    np.save(os.path.join(parent.basename, "spks.npy"), parent.Spks)
+    iscell = np.concatenate(
+        (parent.iscell[:, np.newaxis], parent.probcell[:, np.newaxis]), axis=1)
+    np.save(os.path.join(parent.basename, "iscell.npy"), iscell)
+
+    parent.notmerged = np.ones(parent.iscell.size, "bool")
+
 
 def load_custom_mask(parent):
-    name = QFileDialog.getOpenFileName(
-        parent, "Open *.npy", filter="*.npy"
-    )
+    name = QFileDialog.getOpenFileName(parent, "Open *.npy", filter="*.npy")
     name = name[0]
     cloaded = False
     try:
         mask = np.load(name)
         mask = mask.flatten()
         if mask.size == parent.Fcell.shape[0]:
-            b = len(parent.color_names)-1
+            b = len(parent.color_names) - 1
             parent.colorbtns.button(b).setEnabled(True)
             parent.colorbtns.button(b).setStyleSheet(parent.styleUnpressed)
             cloaded = True
-    except (ValueError, KeyError, OSError,
-            RuntimeError, TypeError, NameError):
+    except (ValueError, KeyError, OSError, RuntimeError, TypeError, NameError):
         print("ERROR: this is not a 1D array with length of data")
     if cloaded:
         parent.custom_mask = mask
         masks.custom_masks(parent)
         M = masks.draw_masks(parent)
-        b = len(parent.colors)+1
+        b = len(parent.colors) + 1
         parent.colorbtns.button(b).setEnabled(True)
         parent.colorbtns.button(b).setStyleSheet(parent.styleUnpressed)
         parent.colorbtns.button(b).setChecked(True)
-        parent.colorbtns.button(b).press(parent,b)
+        parent.colorbtns.button(b).press(parent, b)
         parent.show()
     else:
         print("ERROR: this is not a 1D array with length of # of ROIs")
 
 
 def load_again(parent, Text):
-    tryagain = QMessageBox.question(
-        parent, "ERROR", Text, QMessageBox.Yes | QMessageBox.No
-    )
+    tryagain = QMessageBox.question(parent, "ERROR", Text,
+                                    QMessageBox.Yes | QMessageBox.No)
 
     if tryagain == QMessageBox.Yes:
         load_dialog(parent)
diff --git a/suite2p/gui/masks.py b/suite2p/gui/masks.py
index d6509d575..82c173b12 100644
--- a/suite2p/gui/masks.py
+++ b/suite2p/gui/masks.py
@@ -14,16 +14,9 @@ def make_buttons(parent, b0):
     """ color buttons at row b0 """
     # color buttons
     parent.color_names = [
-        "A: random",
-        "S: skew",
-        "D: compact",
-        "F: footprint",
-        "G: aspect_ratio",
-        "H: chan2_prob",
-        "J: classifier, cell prob=",
-        "K: correlations, bin=",
-        "L: corr with 1D var, bin=^^^",
-        "M: rastermap / custom"
+        "A: random", "S: skew", "D: compact", "F: footprint", "G: aspect_ratio",
+        "H: chan2_prob", "J: classifier, cell prob=", "K: correlations, bin=",
+        "L: corr with 1D var, bin=^^^", "M: rastermap / custom"
     ]
     parent.colorbtns = QButtonGroup(parent)
     clabel = QLabel(parent)
@@ -35,8 +28,10 @@ def make_buttons(parent, b0):
 
     # add colormaps
     parent.CmapChooser = QComboBox()
-    cmaps = ['hsv', 'viridis', 'plasma', 'inferno', 'magma', 'cividis',
-             'viridis_r', 'plasma_r', 'inferno_r', 'magma_r', 'cividis_r']
+    cmaps = [
+        "hsv", "viridis", "plasma", "inferno", "magma", "cividis", "viridis_r",
+        "plasma_r", "inferno_r", "magma_r", "cividis_r"
+    ]
     parent.CmapChooser.addItems(cmaps)
     parent.CmapChooser.setCurrentIndex(0)
     parent.CmapChooser.activated.connect(lambda: cmap_change(parent))
@@ -51,7 +46,7 @@ def make_buttons(parent, b0):
     for names in colorsAll:
         btn = ColorButton(b, "&" + names, parent)
         parent.colorbtns.addButton(btn, b)
-        if b>4 and b<8:
+        if b > 4 and b < 8:
             parent.l0.addWidget(btn, nv + b + 1, 0, 1, 1)
         else:
             parent.l0.addWidget(btn, nv + b + 1, 0, 1, 2)
@@ -69,9 +64,7 @@ def make_buttons(parent, b0):
     parent.probedit.setText("0.5")
     parent.probedit.setFixedWidth(iwid)
     parent.probedit.setAlignment(QtCore.Qt.AlignRight)
-    parent.probedit.returnPressed.connect(
-        lambda: suite2p.gui.merge.apply(parent)
-    )
+    parent.probedit.returnPressed.connect(lambda: suite2p.gui.merge.apply(parent))
     parent.l0.addWidget(parent.probedit, nv + b - 3, 1, 1, 1)
 
     parent.binedit = QLineEdit(parent)
@@ -80,92 +73,95 @@ def make_buttons(parent, b0):
     parent.binedit.setFixedWidth(iwid)
     parent.binedit.setAlignment(QtCore.Qt.AlignRight)
     parent.binedit.returnPressed.connect(
-        lambda: parent.mode_change(parent.activityMode)
-    )
+        lambda: parent.mode_change(parent.activityMode))
     parent.l0.addWidget(parent.binedit, nv + b - 2, 1, 1, 1)
-    b0 = nv+b+2
+    b0 = nv + b + 2
     return b0
 
+
 def cmap_change(parent):
     index = parent.CmapChooser.currentIndex()
-    parent.ops_plot['colormap'] = parent.CmapChooser.itemText(index)
+    parent.ops_plot["colormap"] = parent.CmapChooser.itemText(index)
     if parent.loaded:
-        print('colormap changed to %s, loading...'%parent.ops_plot['colormap'])
-        istat = parent.colors['istat']
+        print("colormap changed to %s, loading..." % parent.ops_plot["colormap"])
+        istat = parent.colors["istat"]
         for c in range(1, istat.shape[0]):
-            parent.colors['cols'][c] = istat_transform(istat[c], parent.ops_plot['colormap'])
-            rgb_masks(parent, parent.colors['cols'][c], c)
-        parent.colormat = draw_colorbar(parent.ops_plot['colormap'])
+            parent.colors["cols"][c] = istat_transform(istat[c],
+                                                       parent.ops_plot["colormap"])
+            rgb_masks(parent, parent.colors["cols"][c], c)
+        parent.colormat = draw_colorbar(parent.ops_plot["colormap"])
         parent.update_plot()
 
+
 def hsv2rgb(cols):
-    cols = cols[:,np.newaxis]
+    cols = cols[:, np.newaxis]
     cols = np.concatenate((cols, np.ones_like(cols), np.ones_like(cols)), axis=-1)
     cols = (255 * hsv_to_rgb(cols)).astype(np.uint8)
     return cols
 
+
 def make_colors(parent):
-    parent.colors['colorbar'] = []
+    parent.colors["colorbar"] = []
     ncells = len(parent.stat)
-    parent.colors['cols'] = np.zeros((len(parent.color_names), ncells, 3), np.uint8)
-    parent.colors['istat'] = np.zeros((len(parent.color_names), ncells), np.float32)
+    parent.colors["cols"] = np.zeros((len(parent.color_names), ncells, 3), np.uint8)
+    parent.colors["istat"] = np.zeros((len(parent.color_names), ncells), np.float32)
     np.random.seed(seed=0)
     allcols = np.random.random((ncells,))
-    if 'meanImg_chan2' in parent.ops:
+    if "meanImg_chan2" in parent.ops:
         allcols = allcols / 1.4
         allcols = allcols + 0.1
-        print(f'number of red cells: {parent.redcell.sum()}')
+        print(f"number of red cells: {parent.redcell.sum()}")
         parent.randcols = allcols.copy()
         allcols[parent.redcell] = 0
     else:
         parent.randcols = allcols
-    parent.colors['istat'][0] = parent.randcols
-    parent.colors['cols'][0] = hsv2rgb(allcols)
+    parent.colors["istat"][0] = parent.randcols
+    parent.colors["cols"][0] = hsv2rgb(allcols)
 
-    b=0
+    b = 0
     for names in parent.color_names[:-3]:
         if b > 0:
-            istat = np.zeros((ncells,1))
-            if b<len(parent.color_names)-2:
+            istat = np.zeros((ncells, 1))
+            if b < len(parent.color_names) - 2:
                 if names in parent.stat[0]:
-                    for n in range(0,ncells):
+                    for n in range(0, ncells):
                         istat[n] = parent.stat[n][names]
-                istat1 = np.percentile(istat,2)
-                istat99 = np.percentile(istat,98)
-                parent.colors['colorbar'].append([istat1,
-                                    (istat99-istat1)/2 + istat1,
-                                    istat99])
+                istat1 = np.percentile(istat, 2)
+                istat99 = np.percentile(istat, 98)
+                parent.colors["colorbar"].append(
+                    [istat1, (istat99 - istat1) / 2 + istat1, istat99])
                 istat = istat - istat1
-                istat = istat / (istat99-istat1)
+                istat = istat / (istat99 - istat1)
                 istat = np.maximum(0, np.minimum(1, istat))
             else:
                 istat = np.expand_dims(parent.probcell, axis=1)
-                parent.parent.colors['colorbar'].append([0.0, .5, 1.0])
-            col = istat_transform(istat, parent.ops_plot['colormap'])
-            parent.colors['cols'][b] = col
-            parent.colors['istat'][b] = istat.flatten()
+                parent.parent.colors["colorbar"].append([0.0, .5, 1.0])
+            col = istat_transform(istat, parent.ops_plot["colormap"])
+            parent.colors["cols"][b] = col
+            parent.colors["istat"][b] = istat.flatten()
         else:
-            parent.colors['colorbar'].append([0,0.5,1])
-        b+=1
-    parent.colors['colorbar'].append([0,0.5,1])
-    parent.colors['colorbar'].append([0,0.5,1])
-    parent.colors['colorbar'].append([0,0.5,1])
+            parent.colors["colorbar"].append([0, 0.5, 1])
+        b += 1
+    parent.colors["colorbar"].append([0, 0.5, 1])
+    parent.colors["colorbar"].append([0, 0.5, 1])
+    parent.colors["colorbar"].append([0, 0.5, 1])
 
     #parent.ops_plot[4] = corrcols
     #parent.cc = cc
 
+
 def flip_plot(parent):
     parent.iflip = parent.ichosen
     for n in parent.imerge:
         iscell = int(parent.iscell[n])
-            
+
         parent.iscell[n] = ~parent.iscell[n]
         parent.ichosen = n
         flip_roi(parent)
-        if 'imerge' in parent.stat[n]:
-            for k in parent.stat[n]['imerge']:
+        if "imerge" in parent.stat[n]:
+            for k in parent.stat[n]["imerge"]:
                 parent.iscell[k] = ~parent.iscell[k]
-        
+
     parent.update_plot()
 
     # Check if `iscell.npy` file exists
@@ -178,6 +174,7 @@ def flip_plot(parent):
 
     io.save_iscell(parent)
 
+
 def chan2_prob(parent):
     chan2prob = float(parent.chan2edit.text())
     if abs(parent.chan2prob - chan2prob) > 1e-3:
@@ -187,6 +184,7 @@ def chan2_prob(parent):
         parent.update_plot()
         io.save_redcell(parent)
 
+
 def make_colorbar(parent, b0):
     colorbarW = pg.GraphicsLayoutWidget(parent)
     colorbarW.setMaximumHeight(60)
@@ -204,6 +202,7 @@ def make_colorbar(parent, b0):
         colorbarW.addLabel("1.0", color=[255, 255, 255], row=1, col=2),
     ]
 
+
 def init_masks(parent):
     """
     creates RGB masks using stat and puts them in M0 or M1 depending on
@@ -220,74 +219,78 @@ def init_masks(parent):
     """
     stat = parent.stat
     iscell = parent.iscell
-    cols = parent.colors['cols']
+    cols = parent.colors["cols"]
     ncells = len(stat)
     Ly = parent.Ly
     Lx = parent.Lx
-    parent.rois['Sroi']   = np.zeros((2,Ly,Lx), 'bool')
-    LamAll = np.zeros((Ly,Lx), np.float32)
+    parent.rois["Sroi"] = np.zeros((2, Ly, Lx), "bool")
+    LamAll = np.zeros((Ly, Lx), np.float32)
     # these have 3 layers
-    parent.rois['Lam']    = np.zeros((2,3,Ly,Lx), np.float32)
-    parent.rois['iROI']   = -1 * np.ones((2,3,Ly,Lx), np.int32)
+    parent.rois["Lam"] = np.zeros((2, 3, Ly, Lx), np.float32)
+    parent.rois["iROI"] = -1 * np.ones((2, 3, Ly, Lx), np.int32)
 
     if parent.checkBoxN.isChecked():
         parent.checkBoxN.setChecked(False)
-            
+
     # ignore merged cells
-    iignore = np.zeros(ncells, 'bool')
+    iignore = np.zeros(ncells, "bool")
     parent.roi_text_labels = []
-    for n in np.arange(ncells-1,-1,-1,int):
-        ypix = stat[n]['ypix']
+    for n in np.arange(ncells - 1, -1, -1, int):
+        ypix = stat[n]["ypix"]
         if ypix is not None and not iignore[n]:
-            if 'imerge' in stat[n]:
-                for k in stat[n]['imerge']:
+            if "imerge" in stat[n]:
+                for k in stat[n]["imerge"]:
                     iignore[k] = True
-                    print(f'ROI {k} in merged ROI')
-            xpix = stat[n]['xpix']
-            lam = stat[n]['lam']
+                    print(f"ROI {k} in merged ROI")
+            xpix = stat[n]["xpix"]
+            lam = stat[n]["lam"]
             lam = lam / lam.sum()
-            i = int(1-iscell[n])
+            i = int(1 - iscell[n])
             # add cell on top
-            parent.rois['iROI'][i,2,ypix,xpix] = parent.rois['iROI'][i,1,ypix,xpix]
-            parent.rois['iROI'][i,1,ypix,xpix] = parent.rois['iROI'][i,0,ypix,xpix]
-            parent.rois['iROI'][i,0,ypix,xpix] = n
+            parent.rois["iROI"][i, 2, ypix, xpix] = parent.rois["iROI"][i, 1, ypix,
+                                                                        xpix]
+            parent.rois["iROI"][i, 1, ypix, xpix] = parent.rois["iROI"][i, 0, ypix,
+                                                                        xpix]
+            parent.rois["iROI"][i, 0, ypix, xpix] = n
 
             # add weighting to all layers
-            parent.rois['Lam'][i,2,ypix,xpix] = parent.rois['Lam'][i,1,ypix,xpix]
-            parent.rois['Lam'][i,1,ypix,xpix] = parent.rois['Lam'][i,0,ypix,xpix]
-            parent.rois['Lam'][i,0,ypix,xpix] = lam
-            parent.rois['Sroi'][i,ypix,xpix] = 1
-            LamAll[ypix,xpix] = lam
-            med = stat[n]['med']
+            parent.rois["Lam"][i, 2, ypix, xpix] = parent.rois["Lam"][i, 1, ypix, xpix]
+            parent.rois["Lam"][i, 1, ypix, xpix] = parent.rois["Lam"][i, 0, ypix, xpix]
+            parent.rois["Lam"][i, 0, ypix, xpix] = lam
+            parent.rois["Sroi"][i, ypix, xpix] = 1
+            LamAll[ypix, xpix] = lam
+            med = stat[n]["med"]
             cell_str = str(n)
         else:
-            cell_str = ''
-            med = (0,0)
-        txt = pg.TextItem(cell_str, color=(180,180,180),
-                          anchor=(0.5,0.5))
+            cell_str = ""
+            med = (0, 0)
+        txt = pg.TextItem(cell_str, color=(180, 180, 180), anchor=(0.5, 0.5))
         txt.setPos(med[1], med[0])
         txt.setFont(QtGui.QFont("Times", 8, weight=QtGui.QFont.Bold))
         parent.roi_text_labels.append(txt)
     parent.roi_text_labels = parent.roi_text_labels[::-1]
 
-    parent.rois['LamMean'] = LamAll[LamAll>1e-10].mean()
-    parent.rois['LamNorm'] = np.maximum(0, np.minimum(1, 0.75*parent.rois['Lam'][:,0]/parent.rois['LamMean']))
-    parent.colors['RGB'] = np.zeros((2,cols.shape[0],Ly,Lx,4), np.uint8)
+    parent.rois["LamMean"] = LamAll[LamAll > 1e-10].mean()
+    parent.rois["LamNorm"] = np.maximum(
+        0, np.minimum(1, 0.75 * parent.rois["Lam"][:, 0] / parent.rois["LamMean"]))
+    parent.colors["RGB"] = np.zeros((2, cols.shape[0], Ly, Lx, 4), np.uint8)
 
     for c in range(0, cols.shape[0]):
         rgb_masks(parent, cols[c], c)
 
+
 def rgb_masks(parent, col, c):
     for i in range(2):
-        #S = np.expand_dims(parent.rois['Sroi'][i],axis=2)
-        H = col[parent.rois['iROI'][i,0], :]
+        #S = np.expand_dims(parent.rois["Sroi"][i],axis=2)
+        H = col[parent.rois["iROI"][i, 0], :]
         #H = np.expand_dims(H,axis=2)
         #hsv = np.concatenate((H,S,S),axis=2)
         #rgb = (hsv_to_rgb(hsv)*255).astype(np.uint8)
-        parent.colors['RGB'][i,c,:,:,:3] = H
+        parent.colors["RGB"][i, c, :, :, :3] = H
 
-def draw_masks(parent): #ops, stat, ops_plot, iscell, ichosen):
-    '''
+
+def draw_masks(parent):  #ops, stat, ops_plot, iscell, ichosen):
+    """
 
     creates RGB masks using stat and puts them in M0 or M1 depending on
     whether or not iscell is True for a given ROI
@@ -300,59 +303,65 @@ def draw_masks(parent): #ops, stat, ops_plot, iscell, ichosen):
         M0: ROIs that are True in iscell
         M1: ROIs that are False in iscell
 
-    '''
-    ncells  = parent.iscell.shape[0]
-    plotROI = parent.ops_plot['ROIs_on']
-    view    = parent.ops_plot['view']
-    color   = parent.ops_plot['color']
-    opacity    = parent.ops_plot['opacity']
+    """
+    ncells = parent.iscell.shape[0]
+    plotROI = parent.ops_plot["ROIs_on"]
+    view = parent.ops_plot["view"]
+    color = parent.ops_plot["color"]
+    opacity = parent.ops_plot["opacity"]
 
-    wplot   = int(1-parent.iscell[parent.ichosen])
+    wplot = int(1 - parent.iscell[parent.ichosen])
     # reset transparency
     for i in range(2):
-        parent.colors['RGB'][i,color,:,:,3] = (opacity[view==0] *
-                                               parent.rois['Sroi'][i] *
-                                               parent.rois['LamNorm'][i]).astype(np.uint8)
-    M = [np.array(parent.colors['RGB'][0,color]), np.array(parent.colors['RGB'][1,color])]
+        parent.colors["RGB"][i, color, :, :,
+                             3] = (opacity[view == 0] * parent.rois["Sroi"][i] *
+                                   parent.rois["LamNorm"][i]).astype(np.uint8)
+    M = [
+        np.array(parent.colors["RGB"][0, color]),
+        np.array(parent.colors["RGB"][1, color])
+    ]
 
-    if view==0:
+    if view == 0:
         for n in parent.imerge:
-            ypix = parent.stat[n]['ypix'].flatten()
-            xpix = parent.stat[n]['xpix'].flatten()
-            v = (parent.rois['iROI'][wplot][:,ypix,xpix]>-1).sum(axis=0) - 1
-            v = 1 - v/3
+            ypix = parent.stat[n]["ypix"].flatten()
+            xpix = parent.stat[n]["xpix"].flatten()
+            v = (parent.rois["iROI"][wplot][:, ypix, xpix] > -1).sum(axis=0) - 1
+            v = 1 - v / 3
             M[wplot] = make_chosen_ROI(M[wplot], ypix, xpix, v)
     else:
         for n in parent.imerge:
-            ycirc = parent.stat[n]['ycirc']
-            xcirc = parent.stat[n]['xcirc']
-            ypix = parent.stat[n]['ypix'].flatten()
-            xpix = parent.stat[n]['xpix'].flatten()
-            M[wplot][ypix,xpix,3] = 0
-            col = parent.colors['cols'][color,n]
+            ycirc = parent.stat[n]["ycirc"]
+            xcirc = parent.stat[n]["xcirc"]
+            ypix = parent.stat[n]["ypix"].flatten()
+            xpix = parent.stat[n]["xpix"].flatten()
+            M[wplot][ypix, xpix, 3] = 0
+            col = parent.colors["cols"][color, n]
             sat = 1
             M[wplot] = make_chosen_circle(M[wplot], ycirc, xcirc, col, sat)
 
-    return M[0],M[1]
+    return M[0], M[1]
 
 
 def make_chosen_ROI(M0, ypix, xpix, v):
-    M0[ypix,xpix,:] = np.tile((255*v[:,np.newaxis]).astype(np.uint8), (1,4))
+    M0[ypix, xpix, :] = np.tile((255 * v[:, np.newaxis]).astype(np.uint8), (1, 4))
     return M0
 
+
 def make_chosen_circle(M0, ycirc, xcirc, col, sat):
     ncirc = ycirc.size
-    M0[ycirc,xcirc,:3] = col#[np.newaxis,:]
-    M0[ycirc,xcirc,3]  = 255
+    M0[ycirc, xcirc, :3] = col  #[np.newaxis,:]
+    M0[ycirc, xcirc, 3] = 255
     return M0
 
+
 def chan2_masks(parent):
     c = 0
     col = parent.randcols.copy()
     col[parent.redcell] = 0
     col = col.flatten()
-    parent.colors['cols'][c] = hsv2rgb(col)
-    rgb_masks(parent, parent.colors['cols'][c], c)
+    parent.colors["cols"][c] = hsv2rgb(col)
+    rgb_masks(parent, parent.colors["cols"][c], c)
+
 
 def custom_masks(parent):
     c = 9
@@ -360,58 +369,62 @@ def custom_masks(parent):
     istat = parent.custom_mask
     istat1 = np.percentile(istat, 1)
     istat99 = np.percentile(istat, 99)
-    cl = [istat1, (istat99-istat1)/2 + istat1, istat99]
+    cl = [istat1, (istat99 - istat1) / 2 + istat1, istat99]
     istat -= istat1
-    istat /= istat99-istat1
+    istat /= istat99 - istat1
     istat = np.maximum(0, np.minimum(1, istat))
 
-    parent.colors['colorbar'][c] = cl
+    parent.colors["colorbar"][c] = cl
     istat = istat / istat.max()
-    col = istat_transform(istat, parent.ops_plot['colormap'])
+    col = istat_transform(istat, parent.ops_plot["colormap"])
 
-    parent.colors['cols'][c] = col
-    parent.colors['istat'][c] = istat.flatten()
+    parent.colors["cols"][c] = col
+    parent.colors["istat"][c] = istat.flatten()
 
     rgb_masks(parent, col, c)
 
+
 def rastermap_masks(parent):
     c = 9
     n = np.array(parent.imerge)
     istat = parent.isort
     # no 1D variable loaded -- leave blank
-    parent.colors['colorbar'][c] = ([0, istat.max()/2, istat.max()])
+    parent.colors["colorbar"][c] = ([0, istat.max() / 2, istat.max()])
 
     istat = istat / istat.max()
-    col = istat_transform(istat, parent.ops_plot['colormap'])
-    col[parent.isort==-1] = 0
-    parent.colors['cols'][c] = col
-    parent.colors['istat'][c] = istat.flatten()
+    col = istat_transform(istat, parent.ops_plot["colormap"])
+    col[parent.isort == -1] = 0
+    parent.colors["cols"][c] = col
+    parent.colors["istat"][c] = istat.flatten()
 
     rgb_masks(parent, col, c)
 
+
 def beh_masks(parent):
     c = 8
     n = np.array(parent.imerge)
-    nb = int(np.floor(parent.beh_resampled.size/parent.bin))
-    sn = np.reshape(parent.beh_resampled[:nb*parent.bin], (nb,parent.bin)).mean(axis=1)
+    nb = int(np.floor(parent.beh_resampled.size / parent.bin))
+    sn = np.reshape(parent.beh_resampled[:nb * parent.bin],
+                    (nb, parent.bin)).mean(axis=1)
     sn -= sn.mean()
     snstd = (sn**2).mean()**0.5
     cc = np.dot(parent.Fbin, sn.T) / parent.Fbin.shape[-1] / (parent.Fstd * snstd)
     cc[n] = cc.mean()
     istat = cc
-    inactive=False
+    inactive = False
     istat_min = istat.min()
     istat_max = istat.max()
     istat = istat - istat.min()
     istat = istat / istat.max()
-    col = istat_transform(istat, parent.ops_plot['colormap'])
-    parent.colors['cols'][c] = col
-    parent.colors['istat'][c] = istat.flatten()
-    parent.colors['colorbar'][c] = [istat_min,
-                          (istat_max-istat_min)/2 + istat_min,
-                          istat_max]
+    col = istat_transform(istat, parent.ops_plot["colormap"])
+    parent.colors["cols"][c] = col
+    parent.colors["istat"][c] = istat.flatten()
+    parent.colors["colorbar"][c] = [
+        istat_min, (istat_max - istat_min) / 2 + istat_min, istat_max
+    ]
     rgb_masks(parent, col, c)
 
+
 def corr_masks(parent):
     c = 7
     n = np.array(parent.imerge)
@@ -420,21 +433,22 @@ def corr_masks(parent):
     cc = np.dot(parent.Fbin, sn.T) / parent.Fbin.shape[-1] / (parent.Fstd * snstd)
     cc[n] = cc.mean()
     istat = cc
-    parent.colors['colorbar'][c] = [istat.min(),
-                         (istat.max()-istat.min())/2 + istat.min(),
-                         istat.max()]
+    parent.colors["colorbar"][c] = [
+        istat.min(), (istat.max() - istat.min()) / 2 + istat.min(),
+        istat.max()
+    ]
     istat = istat - istat.min()
     istat = istat / istat.max()
-    col = istat_transform(istat, parent.ops_plot['colormap'])
-    parent.colors['cols'][c] = col
-    parent.colors['istat'][c] = istat.flatten()
+    col = istat_transform(istat, parent.ops_plot["colormap"])
+    parent.colors["cols"][c] = col
+    parent.colors["istat"][c] = istat.flatten()
 
     rgb_masks(parent, col, c)
 
 
 def flip_for_class(parent, iscell):
     ncells = iscell.size
-    if (iscell==parent.iscell).sum() < 100:
+    if (iscell == parent.iscell).sum() < 100:
         for n in range(ncells):
             if iscell[n] != parent.iscell[n]:
                 parent.iscell[n] = iscell[n]
@@ -444,79 +458,96 @@ def flip_for_class(parent, iscell):
         parent.iscell = iscell
         init_masks(parent)
 
+
 def plot_colorbar(parent):
-    bid = parent.ops_plot['color']
-    if bid==0:
-        parent.colorbar.setImage(np.zeros((20,100,3)))
+    bid = parent.ops_plot["color"]
+    if bid == 0:
+        parent.colorbar.setImage(np.zeros((20, 100, 3)))
     else:
         parent.colorbar.setImage(parent.colormat)
     for k in range(3):
-        parent.clabel[k].setText('%1.2f'%parent.colors['colorbar'][bid][k])
+        parent.clabel[k].setText("%1.2f" % parent.colors["colorbar"][bid][k])
+
 
 def plot_masks(parent, M):
     #M = parent.RGB[:,:,np.newaxis], parent.Alpha[]
     parent.color1.setImage(M[0], levels=(0., 255.))
     parent.color2.setImage(M[1], levels=(0., 255.))
-    
+
     #    parent.p1.addItem(txt)
     parent.color1.show()
     parent.color2.show()
 
+
 def remove_roi(parent, n, i0):
     """
     removes roi n from view i0
     """
-    ypix = parent.stat[n]['ypix']
-    xpix = parent.stat[n]['xpix']
+    ypix = parent.stat[n]["ypix"]
+    xpix = parent.stat[n]["xpix"]
     # cell indices
-    ipix = np.array((parent.rois['iROI'][i0,0,:,:]==n).nonzero()).astype(np.int32)
-    ipix1 = np.array((parent.rois['iROI'][i0,1,:,:]==n).nonzero()).astype(np.int32)
-    ipix2 = np.array((parent.rois['iROI'][i0,2,:,:]==n).nonzero()).astype(np.int32)
+    ipix = np.array((parent.rois["iROI"][i0, 0, :, :] == n).nonzero()).astype(np.int32)
+    ipix1 = np.array((parent.rois["iROI"][i0, 1, :, :] == n).nonzero()).astype(np.int32)
+    ipix2 = np.array((parent.rois["iROI"][i0, 2, :, :] == n).nonzero()).astype(np.int32)
     # get rid of cell and push up overlaps on main views
-    parent.rois['Lam'][i0,0,ipix[0,:],ipix[1,:]] = parent.rois['Lam'][i0,1,ipix[0,:],ipix[1,:]]
-    parent.rois['Lam'][i0,1,ipix[0,:],ipix[1,:]] = 0
-    parent.rois['Lam'][i0,1,ipix1[0,:],ipix1[1,:]] = parent.rois['Lam'][i0,2,ipix1[0,:],ipix1[1,:]]
-    parent.rois['Lam'][i0,2,ipix1[0,:],ipix1[1,:]] = 0
-    parent.rois['Lam'][i0,2,ipix2[0,:],ipix2[1,:]] = 0
-    parent.rois['iROI'][i0,0,ipix[0,:],ipix[1,:]] = parent.rois['iROI'][i0,1,ipix[0,:],ipix[1,:]]
-    parent.rois['iROI'][i0,1,ipix[0,:],ipix[1,:]] = -1
-    parent.rois['iROI'][i0,1,ipix1[0,:],ipix1[1,:]] = parent.rois['iROI'][i0,2,ipix1[0,:],ipix1[1,:]]
-    parent.rois['iROI'][i0,2,ipix1[0,:],ipix1[1,:]] = -1
-    parent.rois['iROI'][i0,2,ipix2[0,:],ipix2[1,:]] = -1
+    parent.rois["Lam"][i0, 0, ipix[0, :],
+                       ipix[1, :]] = parent.rois["Lam"][i0, 1, ipix[0, :], ipix[1, :]]
+    parent.rois["Lam"][i0, 1, ipix[0, :], ipix[1, :]] = 0
+    parent.rois["Lam"][i0, 1, ipix1[0, :],
+                       ipix1[1, :]] = parent.rois["Lam"][i0, 2, ipix1[0, :],
+                                                         ipix1[1, :]]
+    parent.rois["Lam"][i0, 2, ipix1[0, :], ipix1[1, :]] = 0
+    parent.rois["Lam"][i0, 2, ipix2[0, :], ipix2[1, :]] = 0
+    parent.rois["iROI"][i0, 0, ipix[0, :],
+                        ipix[1, :]] = parent.rois["iROI"][i0, 1, ipix[0, :], ipix[1, :]]
+    parent.rois["iROI"][i0, 1, ipix[0, :], ipix[1, :]] = -1
+    parent.rois["iROI"][i0, 1, ipix1[0, :],
+                        ipix1[1, :]] = parent.rois["iROI"][i0, 2, ipix1[0, :],
+                                                           ipix1[1, :]]
+    parent.rois["iROI"][i0, 2, ipix1[0, :], ipix1[1, :]] = -1
+    parent.rois["iROI"][i0, 2, ipix2[0, :], ipix2[1, :]] = -1
 
     # remove +/- 1 ROI exists
-    parent.rois['Sroi'][i0,ypix,xpix] = parent.rois['iROI'][i0,0,ypix,xpix] > 0
+    parent.rois["Sroi"][i0, ypix, xpix] = parent.rois["iROI"][i0, 0, ypix, xpix] > 0
+
+    parent.rois["LamNorm"][i0, ypix, xpix] = np.maximum(
+        0,
+        np.minimum(
+            1, 0.75 * parent.rois["Lam"][i0, 0, ypix, xpix] / parent.rois["LamMean"]))
 
-    parent.rois['LamNorm'][i0,ypix,xpix] = np.maximum(0, np.minimum(1,
-                        0.75*parent.rois['Lam'][i0,0,ypix,xpix]/parent.rois['LamMean']))
 
 def add_roi(parent, n, i):
     """
     add roi n to view i
     """
-    ypix = parent.stat[n]['ypix']
-    xpix = parent.stat[n]['xpix']
-    lam  = parent.stat[n]['lam']
-    parent.rois['iROI'][i,2,ypix,xpix] = parent.rois['iROI'][i,1,ypix,xpix]
-    parent.rois['iROI'][i,1,ypix,xpix] = parent.rois['iROI'][i,0,ypix,xpix]
-    parent.rois['iROI'][i,0,ypix,xpix] = n
-    parent.rois['Lam'][i,2,ypix,xpix]  = parent.rois['Lam'][i,1,ypix,xpix]
-    parent.rois['Lam'][i,1,ypix,xpix]  = parent.rois['Lam'][i,0,ypix,xpix]
-    parent.rois['Lam'][i,0,ypix,xpix]  = lam #/ lam.sum()
+    ypix = parent.stat[n]["ypix"]
+    xpix = parent.stat[n]["xpix"]
+    lam = parent.stat[n]["lam"]
+    parent.rois["iROI"][i, 2, ypix, xpix] = parent.rois["iROI"][i, 1, ypix, xpix]
+    parent.rois["iROI"][i, 1, ypix, xpix] = parent.rois["iROI"][i, 0, ypix, xpix]
+    parent.rois["iROI"][i, 0, ypix, xpix] = n
+    parent.rois["Lam"][i, 2, ypix, xpix] = parent.rois["Lam"][i, 1, ypix, xpix]
+    parent.rois["Lam"][i, 1, ypix, xpix] = parent.rois["Lam"][i, 0, ypix, xpix]
+    parent.rois["Lam"][i, 0, ypix, xpix] = lam  #/ lam.sum()
 
     # set whether or not an ROI + weighting of pixels
-    parent.rois['Sroi'][i,ypix,xpix] = 1
-    parent.rois['LamNorm'][:,ypix,xpix] = np.maximum(0, np.minimum(1, 0.75*parent.rois['Lam'][:,0,ypix,xpix]/parent.rois['LamMean']))
+    parent.rois["Sroi"][i, ypix, xpix] = 1
+    parent.rois["LamNorm"][:, ypix, xpix] = np.maximum(
+        0,
+        np.minimum(1, 0.75 * parent.rois["Lam"][:, 0, ypix, xpix] /
+                   parent.rois["LamMean"]))
+
 
 def redraw_masks(parent, ypix, xpix):
     """
     redraw masks after roi added/removed
     """
-    for c in range(parent.colors['cols'].shape[0]):
+    for c in range(parent.colors["cols"].shape[0]):
         for i in range(2):
-            col = parent.colors['cols'][c]
-            rgb = col[parent.rois['iROI'][i,0,ypix,xpix],:]
-            parent.colors['RGB'][i,c,ypix,xpix,:3] = rgb
+            col = parent.colors["cols"][c]
+            rgb = col[parent.rois["iROI"][i, 0, ypix, xpix], :]
+            parent.colors["RGB"][i, c, ypix, xpix, :3] = rgb
+
 
 def flip_roi(parent):
     """
@@ -524,54 +555,56 @@ def flip_roi(parent):
     there are 3 levels of overlap so this may be buggy if more than 3 cells are on
     top of each other
     """
-    cols = parent.ops_plot['color']
+    cols = parent.ops_plot["color"]
     n = parent.ichosen
-    i = int(1-parent.iscell[n])
-    i0 = 1-i
+    i = int(1 - parent.iscell[n])
+    i0 = 1 - i
     if parent.checkBoxN.isChecked():
-        if i0==0:
+        if i0 == 0:
             parent.p1.removeItem(parent.roi_text_labels[n])
             parent.p2.addItem(parent.roi_text_labels[n])
         else:
             parent.p2.removeItem(parent.roi_text_labels[n])
             parent.p1.addItem(parent.roi_text_labels[n])
-    
+
     # remove ROI
     remove_roi(parent, n, i0)
     # add cell to other side (on top) and push down overlaps
     add_roi(parent, n, i)
     # redraw colors
-    ypix = parent.stat[n]['ypix']
-    xpix = parent.stat[n]['xpix']
+    ypix = parent.stat[n]["ypix"]
+    xpix = parent.stat[n]["xpix"]
     redraw_masks(parent, ypix, xpix)
 
 
-def draw_colorbar(colormap='hsv'):
-    H = np.linspace(0,1,101).astype(np.float32)
+def draw_colorbar(colormap="hsv"):
+    H = np.linspace(0, 1, 101).astype(np.float32)
     rgb = istat_transform(H, colormap)
     colormat = np.expand_dims(rgb, axis=0)
-    colormat = np.tile(colormat,(20,1,1))
+    colormat = np.tile(colormat, (20, 1, 1))
     return colormat
 
+
 def istat_hsv(istat):
     istat = istat / 1.4
-    istat = istat + (0.4/1.4)
+    istat = istat + (0.4 / 1.4)
     icols = 1 - istat
     icols = hsv2rgb(icols.flatten())
     return icols
 
-def istat_transform(istat, colormap='hsv'):
-    if colormap=='hsv':
+
+def istat_transform(istat, colormap="hsv"):
+    if colormap == "hsv":
         icols = istat_hsv(istat)
     else:
         try:
             cmap = matplotlib.cm.get_cmap(colormap)
             icols = istat
-            icols = cmap(icols)[:,:3]
+            icols = cmap(icols)[:, :3]
             icols *= 255
             icols = icols.astype(np.uint8)
         except:
-            print('bad colormap, using hsv')
+            print("bad colormap, using hsv")
             icols = istat_hsv(istat)
     return icols
 
@@ -579,8 +612,9 @@ def istat_transform(istat, colormap='hsv'):
 ### Changes colors of ROIs
 # button group is exclusive (at least one color is always chosen)
 class ColorButton(QPushButton):
+
     def __init__(self, bid, Text, parent=None):
-        super(ColorButton,self).__init__(parent)
+        super(ColorButton, self).__init__(parent)
         self.setText(Text)
         self.setCheckable(True)
         self.setStyleSheet(parent.styleInactive)
@@ -588,19 +622,20 @@ def __init__(self, bid, Text, parent=None):
         self.resize(self.minimumSizeHint())
         self.clicked.connect(lambda: self.press(parent, bid))
         self.show()
+
     def press(self, parent, bid):
         for b in range(len(parent.color_names)):
             if parent.colorbtns.button(b).isEnabled():
                 parent.colorbtns.button(b).setStyleSheet(parent.styleUnpressed)
         self.setStyleSheet(parent.stylePressed)
-        parent.ops_plot['color'] = bid
+        parent.ops_plot["color"] = bid
         if not parent.sizebtns.button(1).isChecked():
-            if bid==0:
-                for b in [1,2]:
+            if bid == 0:
+                for b in [1, 2]:
                     parent.topbtns.button(b).setEnabled(False)
                     parent.topbtns.button(b).setStyleSheet(parent.styleInactive)
             else:
-                for b in [1,2]:
+                for b in [1, 2]:
                     parent.topbtns.button(b).setEnabled(True)
                     parent.topbtns.button(b).setStyleSheet(parent.styleUnpressed)
         else:
diff --git a/suite2p/gui/menus.py b/suite2p/gui/menus.py
index e80c7d19e..b64ea82a8 100644
--- a/suite2p/gui/menus.py
+++ b/suite2p/gui/menus.py
@@ -34,9 +34,7 @@ def mainmenu(parent):
     parent.addAction(loadFolder)
 
     # load a behavioral trace
-    parent.loadBeh = QAction(
-        "Load behavior or stim trace (1D only)", parent
-    )
+    parent.loadBeh = QAction("Load behavior or stim trace (1D only)", parent)
     parent.loadBeh.triggered.connect(lambda: io.load_behavior(parent))
     parent.loadBeh.setEnabled(False)
     parent.addAction(parent.loadBeh)
@@ -51,8 +49,7 @@ def mainmenu(parent):
     # Save NWB file
     parent.saveNWB = QAction("Save NWB file", parent)
     parent.saveNWB.triggered.connect(
-        lambda: save_nwb(get_suite2p_path(parent.basename))
-    )
+        lambda: save_nwb(get_suite2p_path(parent.basename)))
     parent.saveNWB.setEnabled(False)
     parent.addAction(parent.saveNWB)
 
@@ -80,6 +77,7 @@ def mainmenu(parent):
     file_menu.addAction(exportFig)
     file_menu.addAction(parent.manual)
 
+
 def classifier(parent):
     main_menu = parent.menuBar()
     # classifier menu
@@ -91,7 +89,8 @@ def classifier(parent):
     parent.loadClass.setEnabled(False)
     parent.loadMenu.addAction(parent.loadClass)
     parent.loadUClass = QAction("default classifier", parent)
-    parent.loadUClass.triggered.connect(lambda: classgui.load_default_classifier(parent))
+    parent.loadUClass.triggered.connect(
+        lambda: classgui.load_default_classifier(parent))
     parent.loadUClass.setEnabled(False)
     parent.loadMenu.addAction(parent.loadUClass)
     parent.loadSClass = QAction("built-in classifier", parent)
@@ -113,6 +112,7 @@ def classifier(parent):
     class_menu.addAction(parent.resetDefault)
     class_menu.addAction(parent.saveDefault)
 
+
 def visualizations(parent):
     # visualizations menuBar
     main_menu = parent.menuBar()
@@ -127,6 +127,7 @@ def visualizations(parent):
     parent.custommask.setEnabled(False)
     vis_menu.addAction(parent.custommask)
 
+
 def registration(parent):
     # registration menuBar
     main_menu = parent.menuBar()
@@ -142,6 +143,7 @@ def registration(parent):
     reg_menu.addAction(parent.reg)
     reg_menu.addAction(parent.regPC)
 
+
 def mergebar(parent):
     # merge menuBar
     main_menu = parent.menuBar()
@@ -155,38 +157,50 @@ def mergebar(parent):
     merge_menu.addAction(parent.sugMerge)
     merge_menu.addAction(parent.saveMerge)
 
+
 def plugins(parent):
     # plugin menu
     main_menu = parent.menuBar()
     parent.plugins = {}
-    plugin_menu = main_menu.addMenu('&Plugins')
-    for entry_pt in iter_entry_points(group='suite2p.plugin', name=None):
-        plugin_obj = entry_pt.load() # load the advertised class from entry_points
-        parent.plugins[entry_pt.name] = plugin_obj(parent) # initialize an object instance from the loaded class and keep it alive in parent; expose parent to plugin
-        action = QAction(parent.plugins[entry_pt.name].name, parent) # create plugin menu item with the name property of the loaded class
-        action.triggered.connect(parent.plugins[entry_pt.name].trigger) # attach class method 'trigger' to plugin menu action
+    plugin_menu = main_menu.addMenu("&Plugins")
+    for entry_pt in iter_entry_points(group="suite2p.plugin", name=None):
+        plugin_obj = entry_pt.load()  # load the advertised class from entry_points
+        parent.plugins[entry_pt.name] = plugin_obj(
+            parent
+        )  # initialize an object instance from the loaded class and keep it alive in parent; expose parent to plugin
+        action = QAction(
+            parent.plugins[entry_pt.name].name, parent
+        )  # create plugin menu item with the name property of the loaded class
+        action.triggered.connect(parent.plugins[entry_pt.name].trigger
+                                )  # attach class method "trigger" to plugin menu action
         plugin_menu.addAction(action)
 
+
 def run_suite2p(parent):
     RW = rungui.RunWindow(parent)
     RW.show()
 
+
 def manual_label(parent):
     MW = drawroi.ROIDraw(parent)
     MW.show()
 
+
 def vis_window(parent):
     parent.VW = visualize.VisWindow(parent)
     parent.VW.show()
 
+
 def reg_window(parent):
     RW = reggui.BinaryPlayer(parent)
     RW.show()
 
+
 def regPC_window(parent):
     RW = reggui.PCViewer(parent)
     RW.show()
 
+
 def suggest_merge(parent):
     MergeWindow = merge.MergeWindow(parent)
     MergeWindow.show()
diff --git a/suite2p/gui/merge.py b/suite2p/gui/merge.py
index 27ca10e4a..d706ec945 100644
--- a/suite2p/gui/merge.py
+++ b/suite2p/gui/merge.py
@@ -10,17 +10,20 @@
 from ..detection.stats import roi_stats, median_pix
 from ..extraction.dcnv import oasis
 
+
 def distance_matrix(parent, ilist):
     idist = 1e6 * np.ones((len(ilist), len(ilist)))
-    for ij,j in enumerate(ilist):
-        for ik,k in enumerate(ilist):
-            if ij<ik:
-                idist[ij,ik] = (((parent.stat[j]['ypix'][np.newaxis,:] -
-                                  parent.stat[k]['ypix'][:,np.newaxis])**2 +
-                                 (parent.stat[j]['xpix'][np.newaxis,:] -
-                                  parent.stat[k]['xpix'][:,np.newaxis])**2) ** 0.5).mean()
+    for ij, j in enumerate(ilist):
+        for ik, k in enumerate(ilist):
+            if ij < ik:
+                idist[ij,
+                      ik] = (((parent.stat[j]["ypix"][np.newaxis, :] -
+                               parent.stat[k]["ypix"][:, np.newaxis])**2 +
+                              (parent.stat[j]["xpix"][np.newaxis, :] -
+                               parent.stat[k]["xpix"][:, np.newaxis])**2)**0.5).mean()
     return idist
 
+
 def do_merge(parent):
     dm = QMessageBox.question(
         parent,
@@ -33,32 +36,33 @@ def do_merge(parent):
         parent.merged.append(parent.imerge)
         parent.update_plot()
         print(parent.merged)
-        print('merged ROIs')
+        print("merged ROIs")
+
 
 def merge_activity_masks(parent):
-    print('merging activity... this may take some time')
-    i0      = int(1-parent.iscell[parent.ichosen])
+    print("merging activity... this may take some time")
+    i0 = int(1 - parent.iscell[parent.ichosen])
     ypix = np.zeros((0,), np.int32)
     xpix = np.zeros((0,), np.int32)
     lam = np.zeros((0,), np.float32)
-    footprints  = np.array([])
-    F    = np.zeros((0,parent.Fcell.shape[1]), np.float32)
-    Fneu = np.zeros((0,parent.Fcell.shape[1]), np.float32)
+    footprints = np.array([])
+    F = np.zeros((0, parent.Fcell.shape[1]), np.float32)
+    Fneu = np.zeros((0, parent.Fcell.shape[1]), np.float32)
     if parent.hasred:
-        F_chan2    = np.zeros((0,parent.Fcell.shape[1]), np.float32)
-        Fneu_chan2 = np.zeros((0,parent.Fcell.shape[1]), np.float32)
-        if not hasattr(parent, 'F_chan2'):
-            parent.F_chan2 = np.load(os.path.join(parent.basename, 'F_chan2.npy'))
-            parent.Fneu_chan2 = np.load(os.path.join(parent.basename, 'Fneu_chan2.npy'))
+        F_chan2 = np.zeros((0, parent.Fcell.shape[1]), np.float32)
+        Fneu_chan2 = np.zeros((0, parent.Fcell.shape[1]), np.float32)
+        if not hasattr(parent, "F_chan2"):
+            parent.F_chan2 = np.load(os.path.join(parent.basename, "F_chan2.npy"))
+            parent.Fneu_chan2 = np.load(os.path.join(parent.basename, "Fneu_chan2.npy"))
 
     probcell = []
     probredcell = []
     merged_cells = []
     remove_merged = []
     for n in np.array(parent.imerge):
-        if len(parent.stat[n]['imerge']) > 0:
+        if len(parent.stat[n]["imerge"]) > 0:
             remove_merged.append(n)
-            for k in parent.stat[n]['imerge']:
+            for k in parent.stat[n]["imerge"]:
                 merged_cells.append(k)
         else:
             merged_cells.append(n)
@@ -69,11 +73,12 @@ def merge_activity_masks(parent):
         xpix = np.append(xpix, parent.stat[n]["xpix"])
         lam = np.append(lam, parent.stat[n]["lam"])
         footprints = np.append(footprints, parent.stat[n]["footprint"])
-        F    = np.append(F, parent.Fcell[n,:][np.newaxis,:], axis=0)
-        Fneu = np.append(Fneu, parent.Fneu[n,:][np.newaxis,:], axis=0)
+        F = np.append(F, parent.Fcell[n, :][np.newaxis, :], axis=0)
+        Fneu = np.append(Fneu, parent.Fneu[n, :][np.newaxis, :], axis=0)
         if parent.hasred:
-            F_chan2    = np.append(F_chan2, parent.F_chan2[n,:][np.newaxis,:], axis=0)
-            Fneu_chan2 = np.append(Fneu_chan2, parent.Fneu_chan2[n,:][np.newaxis,:], axis=0)
+            F_chan2 = np.append(F_chan2, parent.F_chan2[n, :][np.newaxis, :], axis=0)
+            Fneu_chan2 = np.append(Fneu_chan2, parent.Fneu_chan2[n, :][np.newaxis, :],
+                                   axis=0)
         probcell.append(parent.probcell[n])
         probredcell.append(parent.probredcell[n])
 
@@ -83,32 +88,31 @@ def merge_activity_masks(parent):
     prmean = probredcell.mean()
 
     # remove overlaps
-    ipix = np.concatenate((ypix[:,np.newaxis], xpix[:,np.newaxis]), axis=1)
+    ipix = np.concatenate((ypix[:, np.newaxis], xpix[:, np.newaxis]), axis=1)
     _, goodi = np.unique(ipix, return_index=True, axis=0)
     ypix = ypix[goodi]
     xpix = xpix[goodi]
     lam = lam[goodi]
 
-
     ### compute statistics of merges
     stat0 = {}
-    stat0['imerge'] = merged_cells
-    if 'iplane' in parent.stat[merged_cells[0]]:
-        stat0['iplane'] = parent.stat[merged_cells[0]]['iplane']
-    stat0['ypix'] = ypix
-    stat0['xpix'] = xpix
-    stat0['med'] = median_pix(ypix, xpix)
-    stat0['lam'] = lam / lam.sum()
-
-    if 'aspect' in parent.ops:
-        d0 = np.array([int(parent.ops['aspect']*10), 10])
+    stat0["imerge"] = merged_cells
+    if "iplane" in parent.stat[merged_cells[0]]:
+        stat0["iplane"] = parent.stat[merged_cells[0]]["iplane"]
+    stat0["ypix"] = ypix
+    stat0["xpix"] = xpix
+    stat0["med"] = median_pix(ypix, xpix)
+    stat0["lam"] = lam / lam.sum()
+
+    if "aspect" in parent.ops:
+        d0 = np.array([int(parent.ops["aspect"] * 10), 10])
     else:
-        d0 = parent.ops['diameter']
+        d0 = parent.ops["diameter"]
         if isinstance(d0, int):
             d0 = [d0, d0]
-    
+
     # red prob
-    stat0['chan2_prob'] = -1
+    stat0["chan2_prob"] = -1
     # inmerge
     stat0["inmerge"] = -1
 
@@ -118,17 +122,13 @@ def merge_activity_masks(parent):
     if parent.hasred:
         F_chan2 = F_chan2.mean(axis=0)
         Fneu_chan2 = Fneu_chan2.mean(axis=0)
-    dF = F - parent.ops["neucoeff"]*Fneu
+    dF = F - parent.ops["neucoeff"] * Fneu
     # activity stats
     stat0["skew"] = stats.skew(dF)
     stat0["std"] = dF.std()
 
-    spks = oasis(
-        F=dF[np.newaxis, :],
-        batch_size=parent.ops['batch_size'],
-        tau=parent.ops['tau'],
-        fs=parent.ops['fs']
-    )
+    spks = oasis(F=dF[np.newaxis, :], batch_size=parent.ops["batch_size"],
+                 tau=parent.ops["tau"], fs=parent.ops["fs"])
 
     ### remove previously merged cell from FOV (do not replace)
     for k in remove_merged:
@@ -147,14 +147,18 @@ def merge_activity_masks(parent):
 
     # add cell to structs
     parent.stat = np.concatenate((parent.stat, np.array([stat0])), axis=0)
-    parent.stat =  roi_stats(parent.stat, parent.Ly, parent.Lx, aspect=parent.ops.get('aspect', None), 
-						     diameter=parent.ops.get('diameter', None), do_crop=parent.ops.get('soma_crop', 1))
-    parent.stat[-1]['lam'] = parent.stat[-1]['lam'] * merged_cells.size
-    parent.Fcell = np.concatenate((parent.Fcell, F[np.newaxis,:]), axis=0)
-    parent.Fneu = np.concatenate((parent.Fneu, Fneu[np.newaxis,:]), axis=0)
+    parent.stat = roi_stats(parent.stat, parent.Ly, parent.Lx,
+                            aspect=parent.ops.get("aspect", None),
+                            diameter=parent.ops.get("diameter", None),
+                            do_crop=parent.ops.get("soma_crop", 1))
+    parent.stat[-1]["lam"] = parent.stat[-1]["lam"] * merged_cells.size
+    parent.Fcell = np.concatenate((parent.Fcell, F[np.newaxis, :]), axis=0)
+    parent.Fneu = np.concatenate((parent.Fneu, Fneu[np.newaxis, :]), axis=0)
     if parent.hasred:
-        parent.F_chan2 = np.concatenate((parent.F_chan2, F_chan2[np.newaxis,:]), axis=0)
-        parent.Fneu_chan2 = np.concatenate((parent.Fneu_chan2, Fneu_chan2[np.newaxis,:]), axis=0)
+        parent.F_chan2 = np.concatenate((parent.F_chan2, F_chan2[np.newaxis, :]),
+                                        axis=0)
+        parent.Fneu_chan2 = np.concatenate(
+            (parent.Fneu_chan2, Fneu_chan2[np.newaxis, :]), axis=0)
     parent.Spks = np.concatenate((parent.Spks, spks), axis=0)
     iscell = np.array([parent.iscell[parent.ichosen]], dtype=bool)
     parent.iscell = np.concatenate((parent.iscell, iscell), axis=0)
@@ -162,34 +166,32 @@ def merge_activity_masks(parent):
     parent.probredcell = np.append(parent.probredcell, -1)
     parent.redcell = np.append(parent.redcell, False)
     parent.notmerged = np.append(parent.notmerged, False)
-    
+
     ### for GUI drawing
     ycirc, xcirc = utils.circle(parent.stat[-1]["med"], parent.stat[-1]["radius"])
-    goodi = (
-            (ycirc >= 0)
-            & (xcirc >= 0)
-            & (ycirc < parent.ops["Ly"])
-            & (xcirc < parent.ops["Lx"])
-            )
+    goodi = ((ycirc >= 0) & (xcirc >= 0) & (ycirc < parent.ops["Ly"]) &
+             (xcirc < parent.ops["Lx"]))
     parent.stat[-1]["ycirc"] = ycirc[goodi]
     parent.stat[-1]["xcirc"] = xcirc[goodi]
-    
+
     # * add colors *
     masks.make_colors(parent)
     # recompute binned F
     parent.mode_change(parent.activityMode)
 
     for n in merged_cells:
-        parent.stat[n]['inmerge'] = len(parent.stat)-1
+        parent.stat[n]["inmerge"] = len(parent.stat) - 1
         masks.remove_roi(parent, n, i0)
-    masks.add_roi(parent, len(parent.stat)-1, i0)
+    masks.add_roi(parent, len(parent.stat) - 1, i0)
     masks.redraw_masks(parent, ypix, xpix)
 
+
 class MergeWindow(QDialog):
+
     def __init__(self, parent=None):
         super(MergeWindow, self).__init__(parent)
-        self.setGeometry(700,300,700,700)
-        self.setWindowTitle('Choose merge options')
+        self.setGeometry(700, 300, 700, 700)
+        self.setWindowTitle("Choose merge options")
         self.cwidget = QWidget(self)
         self.layout = QGridLayout()
         self.layout.setVerticalSpacing(2)
@@ -198,51 +200,57 @@ def __init__(self, parent=None):
         self.win = pg.GraphicsLayoutWidget()
         self.layout.addWidget(self.win, 11, 0, 4, 4)
         self.p0 = self.win.addPlot(row=0, col=0)
-        self.p0.setMouseEnabled(x=False,y=False)
-        self.p0.enableAutoRange(x=True,y=True)
+        self.p0.setMouseEnabled(x=False, y=False)
+        self.p0.enableAutoRange(x=True, y=True)
         # initial ops values
-        mkeys = ['corr_thres', 'dist_thres']
-        mlabels = ['correlation threshold', 'euclidean distance threshold']
-        self.ops = {'corr_thres': 0.8, 'dist_thres': 100.0}
-        self.layout.addWidget(QLabel('Press enter in a text box to update params'), 0, 0, 1,2)
-        self.layout.addWidget(QLabel('(Correlations use "activity mode" and "bin" from main GUI)'), 1, 0, 1,2)
-        self.layout.addWidget(QLabel('>>>>>>>>>>>> Parameters <<<<<<<<<<<'), 2, 0, 1,2)
-        self.doMerge = QPushButton('merge selected ROIs', default=False, autoDefault=False)
+        mkeys = ["corr_thres", "dist_thres"]
+        mlabels = ["correlation threshold", "euclidean distance threshold"]
+        self.ops = {"corr_thres": 0.8, "dist_thres": 100.0}
+        self.layout.addWidget(QLabel("Press enter in a text box to update params"), 0,
+                              0, 1, 2)
+        self.layout.addWidget(
+            QLabel("(Correlations use 'activity mode' and 'bin' from main GUI)"), 1, 0,
+            1, 2)
+        self.layout.addWidget(QLabel(">>>>>>>>>>>> Parameters <<<<<<<<<<<"), 2, 0, 1, 2)
+        self.doMerge = QPushButton("merge selected ROIs", default=False,
+                                   autoDefault=False)
         self.doMerge.clicked.connect(lambda: self.do_merge(parent))
         self.doMerge.setEnabled(False)
-        self.layout.addWidget(self.doMerge, 9,0,1,1)
+        self.layout.addWidget(self.doMerge, 9, 0, 1, 1)
 
-        self.suggestMerge = QPushButton('next merge suggestion', default=False, autoDefault=False)
+        self.suggestMerge = QPushButton("next merge suggestion", default=False,
+                                        autoDefault=False)
         self.suggestMerge.clicked.connect(lambda: self.suggest_merge(parent))
         self.suggestMerge.setEnabled(False)
-        self.layout.addWidget(self.suggestMerge, 10,0,1,1)
+        self.layout.addWidget(self.suggestMerge, 10, 0, 1, 1)
 
-        self.nMerge = QLabel('= X possible merges found with these parameters')
-        self.layout.addWidget(self.nMerge, 7,0,1,2)
+        self.nMerge = QLabel("= X possible merges found with these parameters")
+        self.layout.addWidget(self.nMerge, 7, 0, 1, 2)
 
-        self.iMerge = QLabel('suggested ROIs to merge: ')
-        self.layout.addWidget(self.iMerge, 8,0,1,2)
+        self.iMerge = QLabel("suggested ROIs to merge: ")
+        self.layout.addWidget(self.iMerge, 8, 0, 1, 2)
 
         self.editlist = []
         self.keylist = []
-        k=1
-        for lkey,llabel in zip(mkeys, mlabels):
+        k = 1
+        for lkey, llabel in zip(mkeys, mlabels):
             qlabel = QLabel(llabel)
-            qlabel.setFont(QtGui.QFont("Times",weight=QtGui.QFont.Bold))
-            self.layout.addWidget(qlabel, k*2+1,0,1,2)
-            qedit = LineEdit(lkey,self)
+            qlabel.setFont(QtGui.QFont("Times", weight=QtGui.QFont.Bold))
+            self.layout.addWidget(qlabel, k * 2 + 1, 0, 1, 2)
+            qedit = LineEdit(lkey, self)
             qedit.set_text(self.ops)
             qedit.setFixedWidth(90)
             qedit.returnPressed.connect(lambda: self.compute_merge_list(parent))
-            self.layout.addWidget(qedit, k*2+2,0,1,2)
+            self.layout.addWidget(qedit, k * 2 + 2, 0, 1, 2)
             self.editlist.append(qedit)
             self.keylist.append(lkey)
-            k+=1
+            k += 1
 
-        print('creating merge window... this may take some time')
-        self.CC  = np.matmul(parent.Fbin[parent.iscell], parent.Fbin[parent.iscell].T) / parent.Fbin.shape[-1]
-        self.CC /= np.matmul(parent.Fstd[parent.iscell][:,np.newaxis],
-                             parent.Fstd[parent.iscell][np.newaxis,:]) + 1e-3
+        print("creating merge window... this may take some time")
+        self.CC = np.matmul(parent.Fbin[parent.iscell],
+                            parent.Fbin[parent.iscell].T) / parent.Fbin.shape[-1]
+        self.CC /= np.matmul(parent.Fstd[parent.iscell][:, np.newaxis],
+                             parent.Fstd[parent.iscell][np.newaxis, :]) + 1e-3
         self.CC -= np.diag(np.diag(self.CC))
 
         self.compute_merge_list(parent)
@@ -251,44 +259,47 @@ def do_merge(self, parent):
         merge_activity_masks(parent)
         parent.merged.append(parent.imerge)
         parent.update_plot()
-        
-        self.cc_row  = np.matmul(parent.Fbin[parent.iscell], parent.Fbin[-1].T) / parent.Fbin.shape[-1]
+
+        self.cc_row = np.matmul(parent.Fbin[parent.iscell],
+                                parent.Fbin[-1].T) / parent.Fbin.shape[-1]
         self.cc_row /= parent.Fstd[parent.iscell] * parent.Fstd[-1] + 1e-3
         self.cc_row[-1] = 0
         self.CC = np.concatenate((self.CC, self.cc_row[np.newaxis, :-1]), axis=0)
-        self.CC = np.concatenate((self.CC, self.cc_row[:,np.newaxis]), axis=1)
+        self.CC = np.concatenate((self.CC, self.cc_row[:, np.newaxis]), axis=1)
         for n in parent.imerge:
             self.CC[parent.imerge] = 0
-            self.CC[:,parent.imerge] = 0
+            self.CC[:, parent.imerge] = 0
 
-        parent.ichosen = parent.stat.size-1
+        parent.ichosen = parent.stat.size - 1
         parent.imerge = [parent.ichosen]
-        print('ROIs merged: %s'%parent.stat[parent.ichosen]['imerge'])
+        print("ROIs merged: %s" % parent.stat[parent.ichosen]["imerge"])
         self.compute_merge_list(parent)
 
     def compute_merge_list(self, parent):
-        print('computing automated merge suggestions...')
-        for k,key in enumerate(self.keylist):
+        print("computing automated merge suggestions...")
+        for k, key in enumerate(self.keylist):
             self.ops[key] = self.editlist[k].get_text()
         goodind = []
         NN = len(parent.stat[parent.iscell])
-        notused = np.ones(NN, 'bool') # not in a suggested merge
+        notused = np.ones(NN, "bool")  # not in a suggested merge
         icell = np.where(parent.iscell)[0]
         for k in range(NN):
             if notused[k]:
-                ilist = [i for i, x in enumerate(self.CC[k]) if x >= self.ops['corr_thres']]
+                ilist = [
+                    i for i, x in enumerate(self.CC[k]) if x >= self.ops["corr_thres"]
+                ]
                 ilist.append(k)
                 if len(ilist) > 1:
-                    for n,i in enumerate(ilist):
+                    for n, i in enumerate(ilist):
                         if notused[i]:
                             ilist[n] = icell[i]
-                            if parent.stat[ilist[n]]['inmerge'] > 0:
-                                ilist[n] = parent.stat[ilist[n]]['inmerge']
+                            if parent.stat[ilist[n]]["inmerge"] > 0:
+                                ilist[n] = parent.stat[ilist[n]]["inmerge"]
                     ilist = np.unique(np.array(ilist))
                     if ilist.size > 1:
-                        idist = distance_matrix(parent,ilist)
+                        idist = distance_matrix(parent, ilist)
                         idist = idist.min(axis=1)
-                        ilist = ilist[idist <= self.ops['dist_thres']]
+                        ilist = ilist[idist <= self.ops["dist_thres"]]
                         if ilist.size > 1:
                             for i in ilist:
                                 notused[parent.iscell[:i].sum()] = False
@@ -296,7 +307,8 @@ def compute_merge_list(self, parent):
         self.set_merge_list(parent, goodind)
 
     def set_merge_list(self, parent, goodind):
-        self.nMerge.setText('= %d possible merges found with these parameters'%len(goodind))
+        self.nMerge.setText("= %d possible merges found with these parameters" %
+                            len(goodind))
         self.merge_list = goodind
         self.n = 0
         if len(self.merge_list) > 0:
@@ -306,40 +318,44 @@ def set_merge_list(self, parent, goodind):
 
     def suggest_merge(self, parent):
         parent.ichosen = self.merge_list[self.n][0]
-        parent.imerge  = list(self.merge_list[self.n])
+        parent.imerge = list(self.merge_list[self.n])
         if self.unmerged[self.n]:
-            self.iMerge.setText('suggested ROIs to merge: %s'%parent.imerge)
+            self.iMerge.setText("suggested ROIs to merge: %s" % parent.imerge)
             self.doMerge.setEnabled(True)
             self.p0.clear()
             cell0 = parent.imerge[0]
-            sstring = ''
+            sstring = ""
             for i in parent.imerge[1:]:
-                rgb = parent.colors['cols'][0,i]
+                rgb = parent.colors["cols"][0, i]
                 pen = pg.mkPen(rgb, width=3)
-                scatter=pg.ScatterPlotItem(parent.Fbin[cell0], parent.Fbin[i], pen=pen)
+                scatter = pg.ScatterPlotItem(parent.Fbin[cell0], parent.Fbin[i],
+                                             pen=pen)
                 self.p0.addItem(scatter)
-                sstring += ' %d '%i
-            self.p0.setLabel('left', sstring)
-            self.p0.setLabel('bottom', str(cell0))
+                sstring += " %d " % i
+            self.p0.setLabel("left", sstring)
+            self.p0.setLabel("bottom", str(cell0))
         else:
             # set to the merged ROI index
-            parent.ichosen = parent.stat[parent.ichosen]['inmerge']
+            parent.ichosen = parent.stat[parent.ichosen]["inmerge"]
             parent.imerge = [parent.ichosen]
-            self.iMerge.setText('ROIs merged: %s'%list(parent.stat[parent.ichosen]['imerge']))
+            self.iMerge.setText("ROIs merged: %s" %
+                                list(parent.stat[parent.ichosen]["imerge"]))
             self.doMerge.setEnabled(False)
             self.p0.clear()
 
-        self.n+=1
-        if self.n > len(self.merge_list)-1:
+        self.n += 1
+        if self.n > len(self.merge_list) - 1:
             self.n = 0
         parent.checkBoxz.setChecked(True)
         parent.update_plot()
         parent.win.show()
         parent.show()
 
+
 class LineEdit(QLineEdit):
-    def __init__(self,key,parent=None):
-        super(LineEdit,self).__init__(parent)
+
+    def __init__(self, key, parent=None):
+        super(LineEdit, self).__init__(parent)
         self.key = key
         #self.textEdited.connect(lambda: self.edit_changed(parent.ops, k))
 
@@ -348,7 +364,7 @@ def get_text(self):
         okey = float(self.text())
         return okey
 
-    def set_text(self,ops):
+    def set_text(self, ops):
         key = self.key
         dstr = str(ops[key])
         self.setText(dstr)
@@ -359,4 +375,4 @@ def apply(parent):
     iscell = parent.probcell > classval
     masks.flip_for_class(parent, iscell)
     parent.update_plot()
-    io.save_iscell(parent)
\ No newline at end of file
+    io.save_iscell(parent)
diff --git a/suite2p/gui/reggui.py b/suite2p/gui/reggui.py
index a95f699e0..d10a4f121 100644
--- a/suite2p/gui/reggui.py
+++ b/suite2p/gui/reggui.py
@@ -17,23 +17,24 @@
 
 
 class BinaryPlayer(QMainWindow):
+
     def __init__(self, parent=None):
         super(BinaryPlayer, self).__init__(parent)
-        pg.setConfigOptions(imageAxisOrder='row-major')
-        self.setGeometry(70,70,1070,1070)
-        self.setWindowTitle('View registered binary')
+        pg.setConfigOptions(imageAxisOrder="row-major")
+        self.setGeometry(70, 70, 1070, 1070)
+        self.setWindowTitle("View registered binary")
         self.cwidget = QWidget(self)
         self.setCentralWidget(self.cwidget)
         self.l0 = QGridLayout()
         #layout = QtGui.QFormLayout()
         self.cwidget.setLayout(self.l0)
-        #self.p0 = pg.ViewBox(lockAspect=False,name='plot1',border=[100,100,100],invertY=True)
+        #self.p0 = pg.ViewBox(lockAspect=False,name="plot1",border=[100,100,100],invertY=True)
         self.win = pg.GraphicsLayoutWidget()
         # --- cells image
         self.win = pg.GraphicsLayoutWidget()
-        self.win.move(600,0)
-        self.win.resize(1000,500)
-        self.l0.addWidget(self.win,1,2,13,14)
+        self.win.move(600, 0)
+        self.win.resize(1000, 500)
+        self.l0.addWidget(self.win, 1, 2, 13, 14)
         layout = self.win.ci.layout
         self.loaded = False
         self.zloaded = False
@@ -82,39 +83,38 @@ def __init__(self, parent=None):
         self.zbox.toggled.connect(self.add_zstack)
         self.l0.addWidget(self.zbox, 0, 8, 1, 1)
 
-        zlabel = QLabel('Z-plane:')
+        zlabel = QLabel("Z-plane:")
         zlabel.setStyleSheet("color: white;")
         self.l0.addWidget(zlabel, 0, 9, 1, 1)
 
         self.Zedit = QLineEdit(self)
         self.Zedit.setValidator(QtGui.QIntValidator(0, 0))
-        self.Zedit.setText('0')
+        self.Zedit.setText("0")
         self.Zedit.setFixedWidth(30)
         self.Zedit.setAlignment(QtCore.Qt.AlignRight)
         self.l0.addWidget(self.Zedit, 0, 10, 1, 1)
 
-
-        self.p1 = self.win.addPlot(name='plot_shift',row=1,col=0,colspan=2)
-        self.p1.setMouseEnabled(x=True,y=False)
+        self.p1 = self.win.addPlot(name="plot_shift", row=1, col=0, colspan=2)
+        self.p1.setMouseEnabled(x=True, y=False)
         self.p1.setMenuEnabled(False)
         self.scatter1 = pg.ScatterPlotItem()
-        self.scatter1.setData([0,0],[0,0])
+        self.scatter1.setData([0, 0], [0, 0])
         self.p1.addItem(self.scatter1)
 
-        self.p2 = self.win.addPlot(name='plot_F',row=2,col=0,colspan=2)
-        self.p2.setMouseEnabled(x=True,y=False)
+        self.p2 = self.win.addPlot(name="plot_F", row=2, col=0, colspan=2)
+        self.p2.setMouseEnabled(x=True, y=False)
         self.p2.setMenuEnabled(False)
         self.scatter2 = pg.ScatterPlotItem()
-        self.p2.setXLink('plot_shift')
+        self.p2.setXLink("plot_shift")
 
-        self.p3 = self.win.addPlot(name='plot_Z',row=3,col=0,colspan=2)
-        self.p3.setMouseEnabled(x=True,y=False)
+        self.p3 = self.win.addPlot(name="plot_Z", row=3, col=0, colspan=2)
+        self.p3.setMouseEnabled(x=True, y=False)
         self.p3.setMenuEnabled(False)
         self.scatter3 = pg.ScatterPlotItem()
-        self.p3.setXLink('plot_shift')
+        self.p3.setXLink("plot_shift")
 
         #self.p2.autoRange(padding=0.01)
-        self.win.ci.layout.setRowStretchFactor(0,12)
+        self.win.ci.layout.setRowStretchFactor(0, 12)
         self.movieLabel = QLabel("No ops chosen")
         self.movieLabel.setStyleSheet("color: white;")
         self.movieLabel.setAlignment(QtCore.Qt.AlignCenter)
@@ -122,17 +122,17 @@ def __init__(self, parent=None):
         self.cframe = 0
         self.createButtons(parent)
         # create ROI chooser
-        self.l0.addWidget(QLabel(''),6,0,1,2)
+        self.l0.addWidget(QLabel(""), 6, 0, 1, 2)
         qlabel = QLabel(self)
         qlabel.setText("<font color='white'>Selected ROI:</font>")
-        self.l0.addWidget(qlabel,7,0,1,2)
+        self.l0.addWidget(qlabel, 7, 0, 1, 2)
         self.ROIedit = QLineEdit(self)
-        self.ROIedit.setValidator(QtGui.QIntValidator(0,10000))
-        self.ROIedit.setText('0')
+        self.ROIedit.setValidator(QtGui.QIntValidator(0, 10000))
+        self.ROIedit.setText("0")
         self.ROIedit.setFixedWidth(45)
         self.ROIedit.setAlignment(QtCore.Qt.AlignRight)
         self.ROIedit.returnPressed.connect(self.number_chosen)
-        self.l0.addWidget(self.ROIedit, 8,0,1,1)
+        self.l0.addWidget(self.ROIedit, 8, 0, 1, 1)
         # create frame slider
         self.frameLabel = QLabel("Current frame:")
         self.frameLabel.setStyleSheet("color: white;")
@@ -143,22 +143,22 @@ def __init__(self, parent=None):
         self.frameSlider.setTickInterval(5)
         self.frameSlider.setTracking(False)
         self.frameDelta = 10
-        self.l0.addWidget(QLabel(''),12,0,1,1)
-        self.l0.setRowStretch(12,1)
-        self.l0.addWidget(self.frameLabel, 13,0,1,2)
-        self.l0.addWidget(self.frameNumber, 14,0,1,2)
-        self.l0.addWidget(self.frameSlider, 13,2,14,13)
-        self.l0.addWidget(QLabel(''),14,1,1,1)
-        ll = QLabel('(when paused, left/right arrow keys can move slider)')
+        self.l0.addWidget(QLabel(""), 12, 0, 1, 1)
+        self.l0.setRowStretch(12, 1)
+        self.l0.addWidget(self.frameLabel, 13, 0, 1, 2)
+        self.l0.addWidget(self.frameNumber, 14, 0, 1, 2)
+        self.l0.addWidget(self.frameSlider, 13, 2, 14, 13)
+        self.l0.addWidget(QLabel(""), 14, 1, 1, 1)
+        ll = QLabel("(when paused, left/right arrow keys can move slider)")
         ll.setStyleSheet("color: white;")
-        self.l0.addWidget(ll,16,0,1,3)
+        self.l0.addWidget(ll, 16, 0, 1, 3)
         #speedLabel = QLabel("Speed:")
         #self.speedSpinBox = QtGui.QSpinBox()
         #self.speedSpinBox.setRange(1, 9999)
         #self.speedSpinBox.setValue(100)
         #self.speedSpinBox.setSuffix("%")
         self.frameSlider.valueChanged.connect(self.go_to_frame)
-        self.l0.addWidget(self.movieLabel,0,0,1,5)
+        self.l0.addWidget(self.movieLabel, 0, 0, 1, 5)
         self.updateFrameSlider()
         self.updateButtons()
         self.updateTimer = QtCore.QTimer()
@@ -174,9 +174,9 @@ def __init__(self, parent=None):
         self.wraw_wred = False
         self.win.scene().sigMouseClicked.connect(self.plot_clicked)
         # if not a combined recording, automatically open binary
-        if hasattr(parent, 'ops'):
-            if parent.ops['save_path'][-8:]!='combined':
-                filename = os.path.abspath(os.path.join(parent.basename, 'ops.npy'))
+        if hasattr(parent, "ops"):
+            if parent.ops["save_path"][-8:] != "combined":
+                filename = os.path.abspath(os.path.join(parent.basename, "ops.npy"))
                 print(filename)
                 self.Fcell = parent.Fcell
                 self.stat = parent.stat
@@ -202,12 +202,12 @@ def add_red(self):
             self.next_frame()
 
     def zoom_image(self):
-        self.vmain.setRange(yRange=(0,self.LY),xRange=(0,self.LX))
+        self.vmain.setRange(yRange=(0, self.LY), xRange=(0, self.LX))
         if self.raw_on or self.z_on:
             if self.z_on:
-                self.vside.setRange(yRange=(0,self.zLy),xRange=(0,self.zLx))
+                self.vside.setRange(yRange=(0, self.zLy), xRange=(0, self.zLx))
             else:
-                self.vside.setRange(yRange=(0,self.LY),xRange=(0,self.LX))
+                self.vside.setRange(yRange=(0, self.LY), xRange=(0, self.LX))
             self.vside.setXLink("plot1")
             self.vside.setYLink("plot1")
 
@@ -237,10 +237,10 @@ def add_zstack(self):
 
     def next_frame(self):
         # loop after video finishes
-        self.cframe+=1
+        self.cframe += 1
         if self.cframe > self.nframes - 1:
             self.cframe = 0
-            if self.LY>0:
+            if self.LY > 0:
                 for n in range(len(self.reg_file)):
                     self.reg_file[n].seek(0, 0)
             else:
@@ -254,23 +254,30 @@ def next_frame(self):
         self.img = np.zeros((self.LY, self.LX), dtype=np.int16)
         for n in range(len(self.reg_loc)):
             buff = self.reg_file[n].read(self.nbytesread[n])
-            img = np.reshape(np.frombuffer(buff, dtype=np.int16, offset=0),(self.Ly[n],self.Lx[n]))
-            self.img[self.dy[n]:self.dy[n]+self.Ly[n], self.dx[n]:self.dx[n]+self.Lx[n]] = img
-            
+            img = np.reshape(np.frombuffer(buff, dtype=np.int16, offset=0),
+                             (self.Ly[n], self.Lx[n]))
+            self.img[self.dy[n]:self.dy[n] + self.Ly[n],
+                     self.dx[n]:self.dx[n] + self.Lx[n]] = img
+
         if self.wred and self.red_on:
             buff = self.reg_file_chan2.read(self.nbytesread[0])
-            imgred = np.reshape(np.frombuffer(buff, dtype=np.int16, offset=0),(self.Ly[0],self.Lx[0]))[:,:,np.newaxis]
-            self.img = np.concatenate((self.img[:,:,np.newaxis], imgred, np.zeros_like(imgred)), axis=-1)
+            imgred = np.reshape(np.frombuffer(buff, dtype=np.int16, offset=0),
+                                (self.Ly[0], self.Lx[0]))[:, :, np.newaxis]
+            self.img = np.concatenate(
+                (self.img[:, :, np.newaxis], imgred, np.zeros_like(imgred)), axis=-1)
         if self.wraw and self.raw_on:
             buff = self.reg_file_raw.read(self.nbytesread[0])
-            self.imgraw = np.reshape(np.frombuffer(buff, dtype=np.int16, offset=0),(self.Ly[0],self.Lx[0]))
+            self.imgraw = np.reshape(np.frombuffer(buff, dtype=np.int16, offset=0),
+                                     (self.Ly[0], self.Lx[0]))
             if self.wraw_wred:
                 buff = self.reg_file_raw_chan2.read(self.nbytesread[0])
-                imgred_raw = np.reshape(np.frombuffer(buff, dtype=np.int16, offset=0),(self.Ly[0],self.Lx[0]))[:,:,np.newaxis]
-                self.imgraw = np.concatenate((self.imgraw[:,:,np.newaxis], imgred_raw, np.zeros_like(imgred_raw)), axis=-1)
+                imgred_raw = np.reshape(np.frombuffer(buff, dtype=np.int16, offset=0),
+                                        (self.Ly[0], self.Lx[0]))[:, :, np.newaxis]
+                self.imgraw = np.concatenate((self.imgraw[:, :, np.newaxis], imgred_raw,
+                                              np.zeros_like(imgred_raw)), axis=-1)
             self.iside.setImage(self.imgraw, levels=self.srange)
         if self.zloaded and self.z_on:
-            if hasattr(self, 'zmax'):
+            if hasattr(self, "zmax"):
                 self.Zedit.setText(str(self.zmax[self.cframe]))
             self.iside.setImage(self.zstack[int(self.Zedit.text())], levels=self.zrange)
         #if self.maskbox.isChecked():
@@ -282,79 +289,78 @@ def next_frame(self):
         self.imain.setImage(self.img, levels=self.srange)
         self.frameSlider.setValue(self.cframe)
         self.frameNumber.setText(str(self.cframe))
-        self.scatter1.setData([self.cframe,self.cframe],
-                              [self.yoff[self.cframe],self.xoff[self.cframe]],
-                              size=10,brush=pg.mkBrush(255,0,0))
+        self.scatter1.setData([self.cframe, self.cframe],
+                              [self.yoff[self.cframe], self.xoff[self.cframe]], size=10,
+                              brush=pg.mkBrush(255, 0, 0))
         if self.Floaded:
-            self.scatter2.setData([self.cframe,self.cframe],
-                                    [self.ft[self.cframe],self.ft[self.cframe]],size=10,
-                                    brush=pg.mkBrush(255,0,0))
+            self.scatter2.setData([self.cframe, self.cframe],
+                                  [self.ft[self.cframe], self.ft[self.cframe]], size=10,
+                                  brush=pg.mkBrush(255, 0, 0))
         if self.zloaded and self.z_on:
-            self.scatter3.setData([self.cframe,self.cframe],
-                                  [self.zmax[self.cframe],self.zmax[self.cframe]],
-                                  size=10,brush=pg.mkBrush(255,0,0))
+            self.scatter3.setData([self.cframe, self.cframe],
+                                  [self.zmax[self.cframe], self.zmax[self.cframe]],
+                                  size=10, brush=pg.mkBrush(255, 0, 0))
+
     def make_masks(self):
         ncells = len(self.stat)
         np.random.seed(seed=0)
         allcols = np.random.random((ncells,))
-        if hasattr(self, 'redcell'):
+        if hasattr(self, "redcell"):
             allcols = allcols / 1.4
             allcols = allcols + 0.1
             allcols[self.redcell] = 0
         self.colors = masks.hsv2rgb(allcols)
-        self.RGB = -1*np.ones((self.LY, self.LX, 3), np.int32)
-        self.cellpix = -1*np.ones((self.LY, self.LX), np.int32)
+        self.RGB = -1 * np.ones((self.LY, self.LX, 3), np.int32)
+        self.cellpix = -1 * np.ones((self.LY, self.LX), np.int32)
         self.sroi = np.zeros((self.LY, self.LX), np.uint8)
-        
+
         for n in np.nonzero(self.iscell)[0]:
-            ypix = self.stat[n]['ypix'].flatten()
-            xpix = self.stat[n]['xpix'].flatten()
-            if not self.ops[0]['allow_overlap']:
-                ypix = ypix[~self.stat[n]['overlap']]
-                xpix = xpix[~self.stat[n]['overlap']]
+            ypix = self.stat[n]["ypix"].flatten()
+            xpix = self.stat[n]["xpix"].flatten()
+            if not self.ops[0]["allow_overlap"]:
+                ypix = ypix[~self.stat[n]["overlap"]]
+                xpix = xpix[~self.stat[n]["overlap"]]
             yext, xext = utils.boundary(ypix, xpix)
-            if len(yext)>0:
-                goodi = (yext>=0) & (xext>=0) & (yext<self.LY) & (xext<self.LX)
-                self.stat[n]['yext'] = yext[goodi] + 0.5
-                self.stat[n]['xext'] = xext[goodi] + 0.5
+            if len(yext) > 0:
+                goodi = (yext >= 0) & (xext >= 0) & (yext < self.LY) & (xext < self.LX)
+                self.stat[n]["yext"] = yext[goodi] + 0.5
+                self.stat[n]["xext"] = xext[goodi] + 0.5
                 self.sroi[yext[goodi], xext[goodi]] = 200
                 #self.sroi[ypix, xpix] = 100
                 #self.RGB[ypix, xpix] = self.colors[n]
                 self.RGB[yext[goodi], xext[goodi]] = self.colors[n]
             else:
-                self.stat[n]['yext'] = yext
-                self.stat[n]['xext'] = xext
+                self.stat[n]["yext"] = yext
+                self.stat[n]["xext"] = xext
             self.cellpix[ypix, xpix] = n
-        self.mask_bool = self.sroi > 0    
-        self.allmasks = np.concatenate((self.RGB,
-                                        self.sroi[:,:,np.newaxis]), axis=-1)
+        self.mask_bool = self.sroi > 0
+        self.allmasks = np.concatenate((self.RGB, self.sroi[:, :, np.newaxis]), axis=-1)
         self.maskmain.setImage(self.allmasks, levels=[0, 255])
         self.maskside.setImage(self.allmasks, levels=[0, 255])
 
     def plot_trace(self):
         self.p2.clear()
-        self.ft = self.Fcell[self.ichosen,:]
+        self.ft = self.Fcell[self.ichosen, :]
         self.p2.plot(self.ft, pen=self.colors[self.ichosen])
         self.p2.addItem(self.scatter2)
-        self.scatter2.setData([self.cframe],[self.ft[self.cframe]],size=10,
-                                brush=pg.mkBrush(255,0,0))
+        self.scatter2.setData([self.cframe], [self.ft[self.cframe]], size=10,
+                              brush=pg.mkBrush(255, 0, 0))
         self.p2.setLimits(yMin=self.ft.min(), yMax=self.ft.max())
-        self.p2.setRange(xRange=(0,self.nframes),
-                         yRange=(self.ft.min(),self.ft.max()),
-                         padding=0.0)
-        self.p2.setLimits(xMin=0,xMax=self.nframes)
+        self.p2.setRange(xRange=(0, self.nframes),
+                         yRange=(self.ft.min(), self.ft.max()), padding=0.0)
+        self.p2.setLimits(xMin=0, xMax=self.nframes)
 
     def open(self):
-        filename = QFileDialog.getOpenFileName(self,
-                            "Open single-plane ops.npy file",filter="ops*.npy")
+        filename = QFileDialog.getOpenFileName(self, "Open single-plane ops.npy file",
+                                               filter="ops*.npy")
         # load ops in same folder
         if filename:
             print(filename[0])
             self.openFile(filename[0], False)
 
     def open_combined(self):
-        filename = QFileDialog.getExistingDirectory(self,
-                            "Load binaries for all planes (choose folder with planeX folders)")
+        filename = QFileDialog.getExistingDirectory(
+            self, "Load binaries for all planes (choose folder with planeX folders)")
         # load ops in same folder
         if filename:
             print(filename)
@@ -362,8 +368,15 @@ def open_combined(self):
 
     def openCombined(self, save_folder):
         try:
-            plane_folders = natsorted([ f.path for f in os.scandir(save_folder) if f.is_dir() and f.name[:5]=='plane'])
-            ops1 = [np.load(os.path.join(f, 'ops.npy'), allow_pickle=True).item() for f in plane_folders]
+            plane_folders = natsorted([
+                f.path
+                for f in os.scandir(save_folder)
+                if f.is_dir() and f.name[:5] == "plane"
+            ])
+            ops1 = [
+                np.load(os.path.join(f, "ops.npy"), allow_pickle=True).item()
+                for f in plane_folders
+            ]
             self.LY = 0
             self.LX = 0
             self.reg_loc = []
@@ -377,34 +390,36 @@ def openCombined(self, save_folder):
             self.wraw_wred = False
             # check that all binaries still exist
             dy, dx = compute_dydx(ops1)
-            for ipl,ops in enumerate(ops1):
-                #if os.path.isfile(ops['reg_file']):
-                if os.path.isfile(ops['reg_file']):
-                    reg_file = ops['reg_file']
+            for ipl, ops in enumerate(ops1):
+                #if os.path.isfile(ops["reg_file"]):
+                if os.path.isfile(ops["reg_file"]):
+                    reg_file = ops["reg_file"]
                 else:
-                    reg_file = os.path.abspath(os.path.join(os.path.dirname(filename),'plane%d'%ipl, 'data.bin'))
+                    reg_file = os.path.abspath(
+                        os.path.join(os.path.dirname(filename), "plane%d" % ipl,
+                                     "data.bin"))
                 print(reg_file, os.path.isfile(reg_file))
                 self.reg_loc.append(reg_file)
-                self.reg_file.append(open(self.reg_loc[-1], 'rb'))
-                self.Ly.append(ops['Ly'])
-                self.Lx.append(ops['Lx'])
+                self.reg_file.append(open(self.reg_loc[-1], "rb"))
+                self.Ly.append(ops["Ly"])
+                self.Lx.append(ops["Lx"])
                 self.dy.append(dy[ipl])
                 self.dx.append(dx[ipl])
-                self.LY = np.maximum(self.LY, self.Ly[-1]+self.dy[-1])
-                self.LX = np.maximum(self.LX, self.Lx[-1]+self.dx[-1])
+                self.LY = np.maximum(self.LY, self.Ly[-1] + self.dy[-1])
+                self.LX = np.maximum(self.LX, self.Lx[-1] + self.dx[-1])
                 good = True
             self.Floaded = False
-            
+
         except Exception as e:
-            print('ERROR: %s'%e)
+            print("ERROR: %s" % e)
             print("(could be incorrect folder or missing binaries)")
             good = False
             try:
                 for n in range(len(self.reg_loc)):
                     self.reg_file[n].close()
-                print('closed binaries')
+                print("closed binaries")
             except:
-                print('tried to close binaries')
+                print("tried to close binaries")
         if good:
             self.filename = save_folder
             self.ops = ops1
@@ -413,60 +428,75 @@ def openCombined(self, save_folder):
     def openFile(self, filename, fromgui):
         try:
             ops = np.load(filename, allow_pickle=True).item()
-            self.LY = ops['Ly']
-            self.LX = ops['Lx']
-            self.Ly = [ops['Ly']]
-            self.Lx = [ops['Lx']]
+            self.LY = ops["Ly"]
+            self.LX = ops["Lx"]
+            self.Ly = [ops["Ly"]]
+            self.Lx = [ops["Lx"]]
             self.dx = [0]
             self.dy = [0]
-            
-            if os.path.isfile(ops['reg_file']):
-                self.reg_loc = [ops['reg_file']]
+
+            if os.path.isfile(ops["reg_file"]):
+                self.reg_loc = [ops["reg_file"]]
             else:
-                self.reg_loc = [os.path.abspath(os.path.join(os.path.dirname(filename),'data.bin'))]
-            self.reg_file = [open(self.reg_loc[-1],'rb')]
+                self.reg_loc = [
+                    os.path.abspath(os.path.join(os.path.dirname(filename), "data.bin"))
+                ]
+            self.reg_file = [open(self.reg_loc[-1], "rb")]
             self.wraw = False
             self.wred = False
             self.wraw_wred = False
-            if 'reg_file_raw' in ops or 'raw_file' in ops:
-                if self.reg_loc == ops['reg_file']:
-                    if 'reg_file_raw' in ops:
-                        self.reg_loc_raw = ops['reg_file_raw']
+            if "reg_file_raw" in ops or "raw_file" in ops:
+                if self.reg_loc == ops["reg_file"]:
+                    if "reg_file_raw" in ops:
+                        self.reg_loc_raw = ops["reg_file_raw"]
                     else:
-                        self.reg_loc_raw = ops['raw_file']
+                        self.reg_loc_raw = ops["raw_file"]
                 else:
-                    self.reg_loc_raw = os.path.abspath(os.path.join(os.path.dirname(filename),'data_raw.bin'))
+                    self.reg_loc_raw = os.path.abspath(
+                        os.path.join(os.path.dirname(filename), "data_raw.bin"))
                 try:
-                    self.reg_file_raw = open(self.reg_loc_raw,'rb')
-                    self.wraw=True
+                    self.reg_file_raw = open(self.reg_loc_raw, "rb")
+                    self.wraw = True
                 except:
                     self.wraw = False
-            if 'reg_file_chan2' in ops:
-                if self.reg_loc == ops['reg_file']:
-                    self.reg_loc_red = ops['reg_file_chan2']
+            if "reg_file_chan2" in ops:
+                if self.reg_loc == ops["reg_file"]:
+                    self.reg_loc_red = ops["reg_file_chan2"]
                 else:
-                    self.reg_loc_red = os.path.abspath(os.path.join(os.path.dirname(filename),'data_chan2.bin'))
-                self.reg_file_chan2 = open(self.reg_loc_red,'rb')
-                self.wred=True
-            if 'reg_file_raw_chan2' in ops or 'raw_file_chan2' in ops:
-                if self.reg_loc == ops['reg_file']:
-                    if 'reg_file_raw_chan2' in ops:
-                        self.reg_loc_raw_chan2 = ops['reg_file_raw_chan2']
+                    self.reg_loc_red = os.path.abspath(
+                        os.path.join(os.path.dirname(filename), "data_chan2.bin"))
+                self.reg_file_chan2 = open(self.reg_loc_red, "rb")
+                self.wred = True
+            if "reg_file_raw_chan2" in ops or "raw_file_chan2" in ops:
+                if self.reg_loc == ops["reg_file"]:
+                    if "reg_file_raw_chan2" in ops:
+                        self.reg_loc_raw_chan2 = ops["reg_file_raw_chan2"]
                     else:
-                        self.reg_loc_raw_chan2 = ops['raw_file_chan2']
+                        self.reg_loc_raw_chan2 = ops["raw_file_chan2"]
                 else:
-                    self.reg_loc_raw_chan2 = os.path.abspath(os.path.join(os.path.dirname(filename),'data_raw_chan2.bin'))
+                    self.reg_loc_raw_chan2 = os.path.abspath(
+                        os.path.join(os.path.dirname(filename), "data_raw_chan2.bin"))
                 try:
-                    self.reg_file_raw_chan2 = open(self.reg_loc_raw_chan2,'rb')
-                    self.wraw_wred=True
+                    self.reg_file_raw_chan2 = open(self.reg_loc_raw_chan2, "rb")
+                    self.wraw_wred = True
                 except:
                     self.wraw_wred = False
 
             if not fromgui:
-                if os.path.isfile(os.path.abspath(os.path.join(os.path.dirname(filename),'F.npy'))):
-                    self.Fcell = np.load(os.path.abspath(os.path.join(os.path.dirname(filename),'F.npy')))
-                    self.stat =  np.load(os.path.abspath(os.path.join(os.path.dirname(filename),'stat.npy')), allow_pickle=True)
-                    self.iscell =  np.load(os.path.abspath(os.path.join(os.path.dirname(filename),'iscell.npy')), allow_pickle=True)
+                if os.path.isfile(
+                        os.path.abspath(os.path.join(os.path.dirname(filename),
+                                                     "F.npy"))):
+                    self.Fcell = np.load(
+                        os.path.abspath(os.path.join(os.path.dirname(filename),
+                                                     "F.npy")))
+                    self.stat = np.load(
+                        os.path.abspath(
+                            os.path.join(os.path.dirname(filename), "stat.npy")),
+                        allow_pickle=True)
+                    self.iscell = np.load(
+                        os.path.abspath(
+                            os.path.join(os.path.dirname(filename), "iscell.npy")),
+                        allow_pickle=True)
                     self.Floaded = True
                 else:
                     self.Floaded = False
@@ -481,9 +511,9 @@ def openFile(self, filename, fromgui):
             try:
                 for n in range(len(self.reg_loc)):
                     self.reg_file[n].close()
-                print('closed binaries')
+                print("closed binaries")
             except:
-                print('tried to close binaries')
+                print("tried to close binaries")
             good = False
         if good:
             self.filename = filename
@@ -494,11 +524,12 @@ def setup_views(self):
         self.p1.clear()
         self.p2.clear()
         self.ichosen = 0
-        self.ROIedit.setText('0')
+        self.ROIedit.setText("0")
         # get scaling from 100 random frames
         ops = self.ops[-1]
-        frames = subsample_frames(ops, np.minimum(ops['nframes']-1,100), self.reg_loc[-1])
-        self.srange = frames.mean() + frames.std()*np.array([-2,5])
+        frames = subsample_frames(ops, np.minimum(ops["nframes"] - 1, 100),
+                                  self.reg_loc[-1])
+        self.srange = frames.mean() + frames.std() * np.array([-2, 5])
 
         self.movieLabel.setText(self.reg_loc[-1])
         self.nbytesread = []
@@ -506,42 +537,43 @@ def setup_views(self):
             self.nbytesread.append(2 * self.Ly[n] * self.Lx[n])
 
         #aspect ratio
-        if 'aspect' in ops:
-            self.xyrat = ops['aspect']
-        elif 'diameter' in ops and (type(ops["diameter"]) is not int) and (len(ops["diameter"]) > 1):
+        if "aspect" in ops:
+            self.xyrat = ops["aspect"]
+        elif "diameter" in ops and (type(ops["diameter"]) is not int) and (len(
+                ops["diameter"]) > 1):
             self.xyrat = ops["diameter"][0] / ops["diameter"][1]
         else:
             self.xyrat = 1.0
         self.vmain.setAspectLocked(lock=True, ratio=self.xyrat)
         self.vside.setAspectLocked(lock=True, ratio=self.xyrat)
 
-        self.nframes = ops['nframes']
-        self.time_step = 1. / ops['fs'] * 1000 / 5 # 5x real-time
-        self.frameDelta = int(np.maximum(5,self.nframes/200))
+        self.nframes = ops["nframes"]
+        self.time_step = 1. / ops["fs"] * 1000 / 5  # 5x real-time
+        self.frameDelta = int(np.maximum(5, self.nframes / 200))
         self.frameSlider.setSingleStep(self.frameDelta)
         self.currentMovieDirectory = QtCore.QFileInfo(self.filename).path()
         if self.nframes > 0:
             self.updateFrameSlider()
             self.updateButtons()
         # plot ops X-Y offsets
-        if 'yoff' in ops:
-            self.yoff = ops['yoff']
-            self.xoff = ops['xoff']
+        if "yoff" in ops:
+            self.yoff = ops["yoff"]
+            self.xoff = ops["xoff"]
         else:
-            self.yoff = np.zeros((ops['nframes'],))
-            self.xoff = np.zeros((ops['nframes'],))
-        self.p1.plot(self.yoff, pen='g')
-        self.p1.plot(self.xoff, pen='y')
-        self.p1.setRange(xRange=(0,self.nframes),
-                         yRange=(np.minimum(self.yoff.min(),self.xoff.min()),
-                                 np.maximum(self.yoff.max(),self.xoff.max())),
-                         padding=0.0)
-        self.p1.setLimits(xMin=0,xMax=self.nframes)
+            self.yoff = np.zeros((ops["nframes"],))
+            self.xoff = np.zeros((ops["nframes"],))
+        self.p1.plot(self.yoff, pen="g")
+        self.p1.plot(self.xoff, pen="y")
+        self.p1.setRange(
+            xRange=(0, self.nframes),
+            yRange=(np.minimum(self.yoff.min(), self.xoff.min()),
+                    np.maximum(self.yoff.max(), self.xoff.max())), padding=0.0)
+        self.p1.setLimits(xMin=0, xMax=self.nframes)
         self.scatter1 = pg.ScatterPlotItem()
         self.p1.addItem(self.scatter1)
-        self.scatter1.setData([self.cframe,self.cframe],
-                              [self.yoff[self.cframe],self.xoff[self.cframe]],
-                              size=10,brush=pg.mkBrush(255,0,0))
+        self.scatter1.setData([self.cframe, self.cframe],
+                              [self.yoff[self.cframe], self.xoff[self.cframe]], size=10,
+                              brush=pg.mkBrush(255, 0, 0))
 
         if self.wraw:
             self.rawbox.setEnabled(True)
@@ -564,14 +596,16 @@ def setup_views(self):
     def keyPressEvent(self, event):
         bid = -1
         if self.playButton.isEnabled():
-            if event.modifiers() !=  QtCore.Qt.ShiftModifier:
+            if event.modifiers() != QtCore.Qt.ShiftModifier:
                 if event.key() == QtCore.Qt.Key_Left:
                     self.cframe -= self.frameDelta
-                    self.cframe  = np.maximum(0, np.minimum(self.nframes-1, self.cframe))
+                    self.cframe = np.maximum(0, np.minimum(self.nframes - 1,
+                                                           self.cframe))
                     self.frameSlider.setValue(self.cframe)
                 elif event.key() == QtCore.Qt.Key_Right:
                     self.cframe += self.frameDelta
-                    self.cframe  = np.maximum(0, np.minimum(self.nframes-1, self.cframe))
+                    self.cframe = np.maximum(0, np.minimum(self.nframes - 1,
+                                                           self.cframe))
                     self.frameSlider.setValue(self.cframe)
         if event.modifiers() != QtCore.Qt.ShiftModifier:
             if event.key() == QtCore.Qt.Key_Space:
@@ -590,44 +624,42 @@ def cell_chosen(self):
             self.cell_mask()
             self.ROIedit.setText(str(self.ichosen))
             rgb = np.array(self.colors[self.ichosen])
-            self.cellscatter.setData(self.xext, self.yext,
-                                     pen=pg.mkPen(list(rgb)),
-                                     brush=pg.mkBrush(list(rgb)), size=3)
-            self.cellscatter_side.setData(self.xext, self.yext,
-                                     pen=pg.mkPen(list(rgb)),
+            self.cellscatter.setData(self.xext, self.yext, pen=pg.mkPen(list(rgb)),
                                      brush=pg.mkBrush(list(rgb)), size=3)
+            self.cellscatter_side.setData(self.xext, self.yext, pen=pg.mkPen(list(rgb)),
+                                          brush=pg.mkBrush(list(rgb)), size=3)
 
             if self.ichosen >= len(self.stat):
                 self.ichosen = len(self.stat) - 1
             self.cell_mask()
-            self.ft = self.Fcell[self.ichosen,:]
+            self.ft = self.Fcell[self.ichosen, :]
             self.plot_trace()
-            self.p2.setXLink('plot_shift')
+            self.p2.setXLink("plot_shift")
             self.jump_to_frame()
             self.show()
 
-    def plot_clicked(self,event):
+    def plot_clicked(self, event):
         items = self.win.scene().items(event.scenePos())
-        posx  = 0
-        posy  = 0
+        posx = 0
+        posy = 0
         iplot = 0
         zoom = False
         zoomImg = False
         choose = False
         if self.loaded:
             for x in items:
-                if x==self.p1:
+                if x == self.p1:
                     vb = self.p1.vb
                     pos = vb.mapSceneToView(event.scenePos())
                     posx = pos.x()
                     iplot = 1
-                elif x==self.p2 and self.Floaded:
+                elif x == self.p2 and self.Floaded:
                     vb = self.p1.vb
                     pos = vb.mapSceneToView(event.scenePos())
                     posx = pos.x()
                     iplot = 2
-                elif x==self.vmain or x==self.vside:
-                    if event.button()==1:
+                elif x == self.vmain or x == self.vside:
+                    if event.button() == 1:
                         if event.double():
                             self.zoom_image()
                         else:
@@ -635,57 +667,59 @@ def plot_clicked(self,event):
                                 pos = x.mapSceneToView(event.scenePos())
                                 posy = int(pos.x())
                                 posx = int(pos.y())
-                                if posy>=0 and posy<self.LX and posx>=0 and posx<self.LY:
-                                    if self.cellpix[posx,posy] > -1:
-                                        self.ichosen = self.cellpix[posx,posy]
+                                if posy >= 0 and posy < self.LX and posx >= 0 and posx < self.LY:
+                                    if self.cellpix[posx, posy] > -1:
+                                        self.ichosen = self.cellpix[posx, posy]
                                         self.cell_chosen()
-                if iplot==1 or iplot==2:
-                    if event.button()==1:
+                if iplot == 1 or iplot == 2:
+                    if event.button() == 1:
                         if event.double():
-                            zoom=True
+                            zoom = True
                         else:
-                            choose=True
+                            choose = True
         if zoom:
-            self.p1.setRange(xRange=(0,self.nframes))
-            self.p2.setRange(xRange=(0,self.nframes))
-            self.p3.setRange(xRange=(0,self.nframes))
+            self.p1.setRange(xRange=(0, self.nframes))
+            self.p2.setRange(xRange=(0, self.nframes))
+            self.p3.setRange(xRange=(0, self.nframes))
 
         if choose:
             if self.playButton.isEnabled():
-                self.cframe = np.maximum(0, np.minimum(self.nframes-1, int(np.round(posx))))
+                self.cframe = np.maximum(
+                    0, np.minimum(self.nframes - 1, int(np.round(posx))))
                 self.frameSlider.setValue(self.cframe)
                 #self.jump_to_frame()
 
     def load_zstack(self):
-        name = QFileDialog.getOpenFileName(
-            self, "Open zstack", filter="*.tif"
-        )
+        name = QFileDialog.getOpenFileName(self, "Open zstack", filter="*.tif")
         self.fname = name[0]
         try:
             self.zstack = imread(self.fname)
             self.zLy, self.zLx = self.zstack.shape[1:]
             self.Zedit.setValidator(QtGui.QIntValidator(0, self.zstack.shape[0]))
-            self.zrange = [np.percentile(self.zstack,1), np.percentile(self.zstack,99)]
+            self.zrange = [
+                np.percentile(self.zstack, 1),
+                np.percentile(self.zstack, 99)
+            ]
 
             self.computeZ.setEnabled(True)
             self.zloaded = True
             self.zbox.setEnabled(True)
             self.zbox.setChecked(True)
-            self.zmax = np.zeros(self.nframes, 'int')
-            if 'zcorr' in self.ops[0]:
-                if self.zstack.shape[0]==self.ops[0]['zcorr'].shape[0]:
-                    zcorr = self.ops[0]['zcorr']
-                    self.zmax = np.argmax(gaussian_filter1d(zcorr.T.copy(), 2, axis=1), axis=1)
+            self.zmax = np.zeros(self.nframes, "int")
+            if "zcorr" in self.ops[0]:
+                if self.zstack.shape[0] == self.ops[0]["zcorr"].shape[0]:
+                    zcorr = self.ops[0]["zcorr"]
+                    self.zmax = np.argmax(gaussian_filter1d(zcorr.T.copy(), 2, axis=1),
+                                          axis=1)
                     self.plot_zcorr()
-            
-        except Exception as e:
-            print('ERROR: %s'%e)
 
+        except Exception as e:
+            print("ERROR: %s" % e)
 
     def cell_mask(self):
         #self.cmask = np.zeros((self.Ly,self.Lx,3),np.float32)
-        self.yext = self.stat[self.ichosen]['yext']
-        self.xext = self.stat[self.ichosen]['xext']
+        self.yext = self.stat[self.ichosen]["yext"]
+        self.xext = self.stat[self.ichosen]["xext"]
         #self.cmask[self.yext,self.xext,2] = (self.srange[1]-self.srange[0])/2 * np.ones((self.yext.size,),np.float32)
 
     def go_to_frame(self):
@@ -696,7 +730,7 @@ def fitToWindow(self):
         self.movieLabel.setScaledContents(self.fitCheckBox.isChecked())
 
     def updateFrameSlider(self):
-        self.frameSlider.setMaximum(self.nframes-1)
+        self.frameSlider.setMaximum(self.nframes - 1)
         self.frameSlider.setMinimum(0)
         self.frameLabel.setEnabled(True)
         self.frameSlider.setEnabled(True)
@@ -708,18 +742,18 @@ def updateButtons(self):
 
     def createButtons(self, parent):
         iconSize = QtCore.QSize(30, 30)
-        openButton = QPushButton('load ops.npy')
+        openButton = QPushButton("load ops.npy")
         openButton.setToolTip("Open single-plane ops.npy")
         openButton.clicked.connect(self.open)
 
-        openButton2 = QPushButton('load folder')
+        openButton2 = QPushButton("load folder")
         openButton2.setToolTip("Choose a folder with planeX folders to load together")
         openButton2.clicked.connect(self.open_combined)
 
-        loadZ = QPushButton('load z-stack tiff')
+        loadZ = QPushButton("load z-stack tiff")
         loadZ.clicked.connect(self.load_zstack)
 
-        self.computeZ = QPushButton('compute z position')
+        self.computeZ = QPushButton("compute z position")
         self.computeZ.setEnabled(False)
         self.computeZ.clicked.connect(lambda: self.compute_z(parent))
 
@@ -738,8 +772,8 @@ def createButtons(self, parent):
         self.pauseButton.clicked.connect(self.pause)
 
         btns = QButtonGroup(self)
-        btns.addButton(self.playButton,0)
-        btns.addButton(self.pauseButton,1)
+        btns.addButton(self.playButton, 0)
+        btns.addButton(self.pauseButton, 1)
         btns.setExclusive(True)
 
         quitButton = QToolButton()
@@ -748,12 +782,12 @@ def createButtons(self, parent):
         quitButton.setToolTip("Quit")
         quitButton.clicked.connect(self.close)
 
-        self.l0.addWidget(openButton,1,0,1,2)
-        self.l0.addWidget(openButton2,2,0,1,2)
-        self.l0.addWidget(loadZ,3,0,1,2)
-        self.l0.addWidget(self.computeZ,4,0,1,2)
-        self.l0.addWidget(self.playButton,15,0,1,1)
-        self.l0.addWidget(self.pauseButton,15,1,1,1)
+        self.l0.addWidget(openButton, 1, 0, 1, 2)
+        self.l0.addWidget(openButton2, 2, 0, 1, 2)
+        self.l0.addWidget(loadZ, 3, 0, 1, 2)
+        self.l0.addWidget(self.computeZ, 4, 0, 1, 2)
+        self.l0.addWidget(self.playButton, 15, 0, 1, 1)
+        self.l0.addWidget(self.pauseButton, 15, 1, 1, 1)
         #self.l0.addWidget(quitButton,0,1,1,1)
         self.playButton.setEnabled(False)
         self.pauseButton.setEnabled(False)
@@ -761,7 +795,7 @@ def createButtons(self, parent):
 
     def jump_to_frame(self):
         if self.playButton.isEnabled():
-            self.cframe = np.maximum(0, np.minimum(self.nframes-1, self.cframe))
+            self.cframe = np.maximum(0, np.minimum(self.nframes - 1, self.cframe))
             self.cframe = int(self.cframe)
             # seek to absolute position
             for n in range(len(self.reg_file)):
@@ -777,19 +811,18 @@ def jump_to_frame(self):
 
     def start(self):
         if self.cframe < self.nframes - 1:
-            print('playing')
+            print("playing")
             self.playButton.setEnabled(False)
             self.pauseButton.setEnabled(True)
             self.frameSlider.setEnabled(False)
             self.updateTimer.start(self.time_step)
 
-
     def pause(self):
         self.updateTimer.stop()
         self.playButton.setEnabled(True)
         self.pauseButton.setEnabled(False)
         self.frameSlider.setEnabled(True)
-        print('paused')
+        print("paused")
 
     def compute_z(self, parent):
         ops, zcorr = registration.compute_zpos(self.zstack, self.ops[0])
@@ -800,121 +833,123 @@ def compute_z(self, parent):
 
     def plot_zcorr(self):
         self.p3.clear()
-        self.p3.plot(self.zmax, pen='r')
+        self.p3.plot(self.zmax, pen="r")
         self.p3.addItem(self.scatter3)
-        self.p3.setRange(xRange=(0,self.nframes),
-                         yRange=(self.zmax.min(),
-                                 self.zmax.max()+3),
-                         padding=0.0)
-        self.p3.setLimits(xMin=0,xMax=self.nframes)
-        self.p3.setXLink('plot_shift')
+        self.p3.setRange(xRange=(0, self.nframes),
+                         yRange=(self.zmax.min(), self.zmax.max() + 3), padding=0.0)
+        self.p3.setLimits(xMin=0, xMax=self.nframes)
+        self.p3.setXLink("plot_shift")
+
 
 def subsample_frames(ops, nsamps, reg_loc):
-    nFrames = ops['nframes']
-    Ly = ops['Ly']
-    Lx = ops['Lx']
-    frames = np.zeros((nsamps, Ly, Lx), dtype='int16')
+    nFrames = ops["nframes"]
+    Ly = ops["Ly"]
+    Lx = ops["Lx"]
+    frames = np.zeros((nsamps, Ly, Lx), dtype="int16")
     nbytesread = 2 * Ly * Lx
-    istart = np.linspace(0, nFrames, 1+nsamps).astype('int64')
-    reg_file = open(reg_loc, 'rb')
-    for j in range(0,nsamps):
+    istart = np.linspace(0, nFrames, 1 + nsamps).astype("int64")
+    reg_file = open(reg_loc, "rb")
+    for j in range(0, nsamps):
         reg_file.seek(nbytesread * istart[j], 0)
         buff = reg_file.read(nbytesread)
         data = np.frombuffer(buff, dtype=np.int16, offset=0)
         buff = []
-        frames[j,:,:] = np.reshape(data, (Ly, Lx))
+        frames[j, :, :] = np.reshape(data, (Ly, Lx))
     reg_file.close()
     return frames
 
+
 class PCViewer(QMainWindow):
+
     def __init__(self, parent=None):
         super(PCViewer, self).__init__(parent)
-        pg.setConfigOptions(imageAxisOrder='row-major')
-        self.setGeometry(70,70,1300,800)
-        self.setWindowTitle('Metrics for registration')
+        pg.setConfigOptions(imageAxisOrder="row-major")
+        self.setGeometry(70, 70, 1300, 800)
+        self.setWindowTitle("Metrics for registration")
         self.cwidget = QWidget(self)
         self.setCentralWidget(self.cwidget)
         self.l0 = QGridLayout()
         #layout = QtGui.QFormLayout()
         self.cwidget.setLayout(self.l0)
 
-        #self.p0 = pg.ViewBox(lockAspect=False,name='plot1',border=[100,100,100],invertY=True)
+        #self.p0 = pg.ViewBox(lockAspect=False,name="plot1",border=[100,100,100],invertY=True)
         self.win = pg.GraphicsLayoutWidget()
         # --- cells image
         self.win = pg.GraphicsLayoutWidget()
-        self.l0.addWidget(self.win,0,2,13,14)
+        self.l0.addWidget(self.win, 0, 2, 13, 14)
         layout = self.win.ci.layout
         # A plot area (ViewBox + axes) for displaying the image
-        self.p3 = self.win.addPlot(row=0,col=0)
-        self.p3.setMouseEnabled(x=False,y=False)
+        self.p3 = self.win.addPlot(row=0, col=0)
+        self.p3.setMouseEnabled(x=False, y=False)
         self.p3.setMenuEnabled(False)
 
-        self.p0 = self.win.addViewBox(name='plot1',lockAspect=True,row=1,col=0,invertY=True)
-        self.p1 = self.win.addViewBox(lockAspect=True,row=1,col=1,invertY=True)
+        self.p0 = self.win.addViewBox(name="plot1", lockAspect=True, row=1, col=0,
+                                      invertY=True)
+        self.p1 = self.win.addViewBox(lockAspect=True, row=1, col=1, invertY=True)
         self.p1.setMenuEnabled(False)
-        self.p1.setXLink('plot1')
-        self.p1.setYLink('plot1')
-        self.p2 = self.win.addViewBox(lockAspect=True,row=1,col=2,invertY=True)
+        self.p1.setXLink("plot1")
+        self.p1.setYLink("plot1")
+        self.p2 = self.win.addViewBox(lockAspect=True, row=1, col=2, invertY=True)
         self.p2.setMenuEnabled(False)
-        self.p2.setXLink('plot1')
-        self.p2.setYLink('plot1')
-        self.img0=pg.ImageItem()
-        self.img1=pg.ImageItem()
-        self.img2=pg.ImageItem()
+        self.p2.setXLink("plot1")
+        self.p2.setYLink("plot1")
+        self.img0 = pg.ImageItem()
+        self.img1 = pg.ImageItem()
+        self.img2 = pg.ImageItem()
         self.p0.addItem(self.img0)
         self.p1.addItem(self.img1)
         self.p2.addItem(self.img2)
         self.win.scene().sigMouseClicked.connect(self.plot_clicked)
 
-        self.p4 = self.win.addPlot(row=0,col=1,colspan=2)
+        self.p4 = self.win.addPlot(row=0, col=1, colspan=2)
         self.p4.setMouseEnabled(x=False)
         self.p4.setMenuEnabled(False)
 
         self.PCedit = QLineEdit(self)
-        self.PCedit.setText('1')
+        self.PCedit.setText("1")
         self.PCedit.setFixedWidth(40)
         self.PCedit.setAlignment(QtCore.Qt.AlignRight)
         self.PCedit.returnPressed.connect(self.plot_frame)
         self.PCedit.textEdited.connect(self.pause)
-        qlabel = QLabel('PC: ')
+        qlabel = QLabel("PC: ")
         boldfont = QtGui.QFont("Arial", 14, QtGui.QFont.Bold)
         bigfont = QtGui.QFont("Arial", 14)
         qlabel.setFont(boldfont)
         self.PCedit.setFont(bigfont)
-        qlabel.setStyleSheet('color: white;')
+        qlabel.setStyleSheet("color: white;")
         #qlabel.setAlignment(QtCore.Qt.AlignRight)
-        self.l0.addWidget(QLabel(''),1,0,1,1)
-        self.l0.addWidget(qlabel,2,0,1,1)
-        self.l0.addWidget(self.PCedit,2,1,1,1)
+        self.l0.addWidget(QLabel(""), 1, 0, 1, 1)
+        self.l0.addWidget(qlabel, 2, 0, 1, 1)
+        self.l0.addWidget(self.PCedit, 2, 1, 1, 1)
         self.nums = []
-        self.titles=[]
+        self.titles = []
         for j in range(3):
-            num1 = QLabel('')
-            num1.setStyleSheet('color: white;')
-            self.l0.addWidget(num1,3+j,0,1,2)
+            num1 = QLabel("")
+            num1.setStyleSheet("color: white;")
+            self.l0.addWidget(num1, 3 + j, 0, 1, 2)
             self.nums.append(num1)
-            t1 = QLabel('')
-            t1.setStyleSheet('color: white;')
-            self.l0.addWidget(t1,12,4+j*4,1,2)
+            t1 = QLabel("")
+            t1.setStyleSheet("color: white;")
+            self.l0.addWidget(t1, 12, 4 + j * 4, 1, 2)
             self.titles.append(t1)
         self.loaded = False
         self.wraw = False
         self.wred = False
         self.wraw_wred = False
-        self.l0.addWidget(QLabel(''),7,0,1,1)
-        self.l0.setRowStretch(7,1)
+        self.l0.addWidget(QLabel(""), 7, 0, 1, 1)
+        self.l0.setRowStretch(7, 1)
         self.cframe = 0
         self.createButtons()
         self.nPCs = 50
-        self.PCedit.setValidator(QtGui.QIntValidator(1,self.nPCs))
+        self.PCedit.setValidator(QtGui.QIntValidator(1, self.nPCs))
         # play button
         self.updateTimer = QtCore.QTimer()
         self.updateTimer.timeout.connect(self.next_frame)
         #self.win.scene().sigMouseClicked.connect(self.plot_clicked)
         # if not a combined recording, automatically open binary
-        if hasattr(parent, 'ops'):
-            if parent.ops['save_path'][-8:]!='combined':
-                filename = os.path.abspath(os.path.join(parent.basename, 'ops.npy'))
+        if hasattr(parent, "ops"):
+            if parent.ops["save_path"][-8:] != "combined":
+                filename = os.path.abspath(os.path.join(parent.basename, "ops.npy"))
                 print(filename)
                 self.openFile(filename)
 
@@ -941,13 +976,13 @@ def createButtons(self):
         self.pauseButton.clicked.connect(self.pause)
 
         btns = QButtonGroup(self)
-        btns.addButton(self.playButton,0)
-        btns.addButton(self.pauseButton,1)
+        btns.addButton(self.playButton, 0)
+        btns.addButton(self.pauseButton, 1)
         btns.setExclusive(True)
 
-        self.l0.addWidget(openButton,0,0,1,1)
-        self.l0.addWidget(self.playButton,14,12,1,1)
-        self.l0.addWidget(self.pauseButton,14,13,1,1)
+        self.l0.addWidget(openButton, 0, 0, 1, 1)
+        self.l0.addWidget(self.playButton, 14, 12, 1, 1)
+        self.l0.addWidget(self.pauseButton, 14, 13, 1, 1)
         #self.l0.addWidget(quitButton,0,1,1,1)
         self.playButton.setEnabled(False)
         self.pauseButton.setEnabled(False)
@@ -966,8 +1001,8 @@ def pause(self):
         self.pauseButton.setEnabled(False)
 
     def open(self):
-        filename = QFileDialog.getOpenFileName(self,
-                            "Open single-plane ops.npy file",filter="ops*.npy")
+        filename = QFileDialog.getOpenFileName(self, "Open single-plane ops.npy file",
+                                               filter="ops*.npy")
         # load ops in same folder
         if filename:
             print(filename[0])
@@ -976,133 +1011,131 @@ def open(self):
     def openFile(self, filename):
         try:
             ops = np.load(filename, allow_pickle=True).item()
-            self.PC = ops['regPC']
-            self.PC = np.clip(self.PC, np.percentile(self.PC, 1), 
-                                np.percentile(self.PC, 99))
-            
+            self.PC = ops["regPC"]
+            self.PC = np.clip(self.PC, np.percentile(self.PC, 1),
+                              np.percentile(self.PC, 99))
+
             self.Ly, self.Lx = self.PC.shape[2:]
-            self.DX = ops['regDX']
-            if 'tPC' in ops:
-                self.tPC = ops['tPC']
+            self.DX = ops["regDX"]
+            if "tPC" in ops:
+                self.tPC = ops["tPC"]
             else:
-                self.tPC = np.zeros((1,self.PC.shape[1]))
+                self.tPC = np.zeros((1, self.PC.shape[1]))
             good = True
         except Exception as e:
             print("ERROR: ops.npy incorrect / missing ops['regPC'] and ops['regDX']")
             print(e)
             good = False
         if good:
-            self.loaded=True
+            self.loaded = True
             self.nPCs = self.PC.shape[1]
-            self.PCedit.setValidator(QtGui.QIntValidator(1,self.nPCs))
+            self.PCedit.setValidator(QtGui.QIntValidator(1, self.nPCs))
             self.plot_frame()
             self.playButton.setEnabled(True)
 
     def next_frame(self):
         iPC = int(self.PCedit.text()) - 1
-        pc1 = self.PC[1,iPC,:,:]
-        pc0 = self.PC[0,iPC,:,:]
-        if self.cframe==0:
-            self.img2.setImage(np.tile(pc0[:,:,np.newaxis],(1,1,3)))
-            self.titles[2].setText('top')
+        pc1 = self.PC[1, iPC, :, :]
+        pc0 = self.PC[0, iPC, :, :]
+        if self.cframe == 0:
+            self.img2.setImage(np.tile(pc0[:, :, np.newaxis], (1, 1, 3)))
+            self.titles[2].setText("top")
 
         else:
-            self.img2.setImage(np.tile(pc1[:,:,np.newaxis],(1,1,3)))
-            self.titles[2].setText('bottom')
+            self.img2.setImage(np.tile(pc1[:, :, np.newaxis], (1, 1, 3)))
+            self.titles[2].setText("bottom")
 
-        self.img2.setLevels([pc0.min(),pc0.max()])
-        self.cframe = 1-self.cframe
+        self.img2.setLevels([pc0.min(), pc0.max()])
+        self.cframe = 1 - self.cframe
 
     def plot_frame(self):
         if self.loaded:
-            self.titles[0].setText('difference')
-            self.titles[1].setText('merged')
-            self.titles[2].setText('top')
+            self.titles[0].setText("difference")
+            self.titles[1].setText("merged")
+            self.titles[2].setText("top")
             iPC = int(self.PCedit.text()) - 1
-            pc1 = self.PC[1,iPC,:,:]
-            pc0 = self.PC[0,iPC,:,:]
-            diff = pc1[:,:,np.newaxis]-pc0[:,:,np.newaxis]
-            diff /= np.abs(diff).max()*2
+            pc1 = self.PC[1, iPC, :, :]
+            pc0 = self.PC[0, iPC, :, :]
+            diff = pc1[:, :, np.newaxis] - pc0[:, :, np.newaxis]
+            diff /= np.abs(diff).max() * 2
             diff += 0.5
-            self.img0.setImage(np.tile(diff*255,(1,1,3)))
-            self.img0.setLevels([0,255])
-            rgb = np.zeros((self.PC.shape[2], self.PC.shape[3],3), np.float32)
-            rgb[:,:,0] = (pc1-pc1.min())/(pc1.max()-pc1.min())*255
-            rgb[:,:,1] = np.minimum(1, np.maximum(0,(pc0-pc1.min())/(pc1.max()-pc1.min())))*255
-            rgb[:,:,2] = (pc1-pc1.min())/(pc1.max()-pc1.min())*255
+            self.img0.setImage(np.tile(diff * 255, (1, 1, 3)))
+            self.img0.setLevels([0, 255])
+            rgb = np.zeros((self.PC.shape[2], self.PC.shape[3], 3), np.float32)
+            rgb[:, :, 0] = (pc1 - pc1.min()) / (pc1.max() - pc1.min()) * 255
+            rgb[:, :, 1] = np.minimum(
+                1, np.maximum(0, (pc0 - pc1.min()) / (pc1.max() - pc1.min()))) * 255
+            rgb[:, :, 2] = (pc1 - pc1.min()) / (pc1.max() - pc1.min()) * 255
             self.img1.setImage(rgb)
-            if self.cframe==0:
-                self.img2.setImage(np.tile(pc0[:,:,np.newaxis],(1,1,3)))
+            if self.cframe == 0:
+                self.img2.setImage(np.tile(pc0[:, :, np.newaxis], (1, 1, 3)))
             else:
-                self.img2.setImage(np.tile(pc1[:,:,np.newaxis],(1,1,3)))
-            self.img2.setLevels([pc0.min(),pc0.max()])
+                self.img2.setImage(np.tile(pc1[:, :, np.newaxis], (1, 1, 3)))
+            self.img2.setLevels([pc0.min(), pc0.max()])
             self.zoom_plot()
             self.p3.clear()
-            p = [(200,200,255),(255,100,100),(100,50,200)]
-            ptitle = ['rigid','nonrigid','nonrigid max']
-            if not hasattr(self,'leg'):
-                self.leg = pg.LegendItem((100,60),offset=(350,30))
+            p = [(200, 200, 255), (255, 100, 100), (100, 50, 200)]
+            ptitle = ["rigid", "nonrigid", "nonrigid max"]
+            if not hasattr(self, "leg"):
+                self.leg = pg.LegendItem((100, 60), offset=(350, 30))
                 self.leg.setParentItem(self.p3)
                 drawLeg = True
             else:
                 drawLeg = False
             for j in range(3):
-                cj = self.p3.plot(np.arange(1,self.nPCs+1),self.DX[:,j],pen=p[j])
+                cj = self.p3.plot(np.arange(1, self.nPCs + 1), self.DX[:, j], pen=p[j])
                 if drawLeg:
-                    self.leg.addItem(cj,ptitle[j])
-                self.nums[j].setText('%s: %1.3f'%(ptitle[j],self.DX[iPC,j]))
+                    self.leg.addItem(cj, ptitle[j])
+                self.nums[j].setText("%s: %1.3f" % (ptitle[j], self.DX[iPC, j]))
             self.scatter = pg.ScatterPlotItem()
             self.p3.addItem(self.scatter)
-            self.scatter.setData([iPC+1,iPC+1,iPC+1],self.DX[iPC,:].tolist(),
-                                 size=10,brush=pg.mkBrush(255,255,255))
-            self.p3.setLabel('left', 'pixel shift')
-            self.p3.setLabel('bottom', 'PC #')
+            self.scatter.setData([iPC + 1, iPC + 1, iPC + 1], self.DX[iPC, :].tolist(),
+                                 size=10, brush=pg.mkBrush(255, 255, 255))
+            self.p3.setLabel("left", "pixel shift")
+            self.p3.setLabel("bottom", "PC #")
 
             self.p4.clear()
-            self.p4.plot(self.tPC[:,iPC])
-            self.p4.setLabel('left', 'magnitude')
-            self.p4.setLabel('bottom', 'time')
+            self.p4.plot(self.tPC[:, iPC])
+            self.p4.setLabel("left", "magnitude")
+            self.p4.setLabel("bottom", "time")
             self.show()
             self.zoom_plot()
 
     def zoom_plot(self):
-        self.p0.setXRange(0,self.Lx)
-        self.p0.setYRange(0,self.Ly)
-        self.p1.setXRange(0,self.Lx)
-        self.p1.setYRange(0,self.Ly)
-        self.p2.setXRange(0,self.Lx)
-        self.p2.setYRange(0,self.Ly)
-
-
-    def plot_clicked(self,event):
+        self.p0.setXRange(0, self.Lx)
+        self.p0.setYRange(0, self.Ly)
+        self.p1.setXRange(0, self.Lx)
+        self.p1.setYRange(0, self.Ly)
+        self.p2.setXRange(0, self.Lx)
+        self.p2.setYRange(0, self.Ly)
+
+    def plot_clicked(self, event):
         items = self.win.scene().items(event.scenePos())
-        posx  = 0
-        posy  = 0
+        posx = 0
+        posy = 0
         iplot = 0
         zoom = False
         if self.loaded:
             for x in items:
-                if x==self.p0 or x==self.p1 or x==self.p2:
-                    if event.button()==1:
+                if x == self.p0 or x == self.p1 or x == self.p2:
+                    if event.button() == 1:
                         if event.double():
-                            zoom=True
+                            zoom = True
                             self.zoom_plot()
 
-
-
     def keyPressEvent(self, event):
         bid = -1
-        if event.modifiers() !=  QtCore.Qt.ShiftModifier:
+        if event.modifiers() != QtCore.Qt.ShiftModifier:
             if event.key() == QtCore.Qt.Key_Left:
                 self.pause()
                 ipc = int(self.PCedit.text())
-                ipc = max(ipc-1, 1)
+                ipc = max(ipc - 1, 1)
                 self.PCedit.setText(str(ipc))
                 self.plot_frame()
             elif event.key() == QtCore.Qt.Key_Right:
                 self.pause()
                 ipc = int(self.PCedit.text())
-                ipc = min(ipc+1, self.nPCs)
+                ipc = min(ipc + 1, self.nPCs)
                 self.PCedit.setText(str(ipc))
                 self.plot_frame()
             elif event.key() == QtCore.Qt.Key_Space:
@@ -1111,4 +1144,4 @@ def keyPressEvent(self, event):
                     self.playButton.setChecked(True)
                     self.start()
                 else:
-                    self.pause()
\ No newline at end of file
+                    self.pause()
diff --git a/suite2p/gui/rungui.py b/suite2p/gui/rungui.py
index a5c085d6f..aa54f9f7d 100644
--- a/suite2p/gui/rungui.py
+++ b/suite2p/gui/rungui.py
@@ -11,35 +11,39 @@
 from . import io
 from .. import default_ops
 
-
 ### ---- this file contains helper functions for GUI and the RUN window ---- ###
 
+
 # type in h5py key
 class TextChooser(QDialog):
-    def __init__(self,parent=None):
+
+    def __init__(self, parent=None):
         super(TextChooser, self).__init__(parent)
-        self.setGeometry(300,300,180,100)
-        self.setWindowTitle('h5 key')
+        self.setGeometry(300, 300, 180, 100)
+        self.setWindowTitle("h5 key")
         self.win = QWidget(self)
         layout = QGridLayout()
         self.win.setLayout(layout)
-        self.qedit = QLineEdit('data')
-        layout.addWidget(QLabel('h5 key for data field'),0,0,1,3)
-        layout.addWidget(self.qedit,1,0,1,2)
-        done = QPushButton('OK')
+        self.qedit = QLineEdit("data")
+        layout.addWidget(QLabel("h5 key for data field"), 0, 0, 1, 3)
+        layout.addWidget(self.qedit, 1, 0, 1, 2)
+        done = QPushButton("OK")
         done.clicked.connect(self.exit_list)
-        layout.addWidget(done,2,1,1,1)
+        layout.addWidget(done, 2, 1, 1, 1)
 
     def exit_list(self):
         self.h5_key = self.qedit.text()
         self.accept()
 
+
 ### custom QDialog which allows user to fill in ops and run suite2p!
 class RunWindow(QDialog):
+
     def __init__(self, parent=None):
         super(RunWindow, self).__init__(parent)
-        self.setGeometry(10,10,1500,900)
-        self.setWindowTitle('Choose run options (hold mouse over parameters to see descriptions)')
+        self.setGeometry(10, 10, 1500, 900)
+        self.setWindowTitle(
+            "Choose run options (hold mouse over parameters to see descriptions)")
         self.parent = parent
         self.win = QWidget(self)
         self.layout = QGridLayout()
@@ -48,20 +52,21 @@ def __init__(self, parent=None):
         self.win.setLayout(self.layout)
         # initial ops values
         self.opsfile = parent.opsuser
-        self.ops_path = os.fspath(pathlib.Path.home().joinpath('.suite2p').joinpath('ops').absolute())
+        self.ops_path = os.fspath(
+            pathlib.Path.home().joinpath(".suite2p").joinpath("ops").absolute())
         try:
             self.reset_ops()
-            print('loaded default ops')
+            print("loaded default ops")
         except Exception as e:
-            print('ERROR: %s'%e)
-            print('could not load default ops, using built-in ops settings')
+            print("ERROR: %s" % e)
+            print("could not load default ops, using built-in ops settings")
             self.ops = default_ops()
 
         # remove any remaining ops files
-        fs = glob.glob('ops*.npy')
+        fs = glob.glob("ops*.npy")
         for f in fs:
             os.remove(f)
-        fs = glob.glob('db*.npy')
+        fs = glob.glob("db*.npy")
         for f in fs:
             os.remove(f)
 
@@ -77,126 +82,156 @@ def reset_ops(self):
         self.ops = np.load(self.opsfile, allow_pickle=True).item()
         ops0 = default_ops()
         self.ops = {**ops0, **self.ops}
-        if hasattr(self, 'editlist'):
+        if hasattr(self, "editlist"):
             for k in range(len(self.editlist)):
                 self.editlist[k].set_text(self.ops)
 
     def create_buttons(self):
-        self.intkeys = ['nplanes', 'nchannels', 'functional_chan', 'align_by_chan', 'nimg_init',
-                   'batch_size', 'max_iterations', 'nbinned','inner_neuropil_radius',
-                   'min_neuropil_pixels', 'spatial_scale', 'do_registration', 'anatomical_only']
-        self.boolkeys = ['delete_bin', 'move_bin','do_bidiphase', 'reg_tif', 'reg_tif_chan2',
-                     'save_mat', 'save_NWB' 'combined', '1Preg', 'nonrigid', 
-                    'connected', 'roidetect', 'neuropil_extract', 
-                    'spikedetect', 'keep_movie_raw', 'allow_overlap', 'sparse_mode']
-        self.stringkeys = ['pretrained_model']
-        tifkeys = ['nplanes','nchannels','functional_chan','tau','fs','do_bidiphase','bidiphase', 'multiplane_parallel', 'ignore_flyback']
-        outkeys = ['preclassify','save_mat','save_NWB','combined','reg_tif','reg_tif_chan2','aspect','delete_bin','move_bin']
-        regkeys = ['do_registration','align_by_chan','nimg_init','batch_size','smooth_sigma', 'smooth_sigma_time','maxregshift','th_badframes','keep_movie_raw','two_step_registration']
-        nrkeys = [['nonrigid','block_size','snr_thresh','maxregshiftNR'], ['1Preg','spatial_hp_reg','pre_smooth','spatial_taper']]
-        cellkeys = ['roidetect', 'sparse_mode', 'denoise', 'spatial_scale', 'threshold_scaling', 'max_overlap','max_iterations','high_pass','spatial_hp_detect']
-        anatkeys = ['anatomical_only', 'diameter', 'cellprob_threshold', 'flow_threshold', 'pretrained_model', 'spatial_hp_cp']
-        neudeconvkeys = [['neuropil_extract', 'allow_overlap','inner_neuropil_radius','min_neuropil_pixels'], ['soma_crop','spikedetect','win_baseline','sig_baseline','neucoeff']]
+        self.intkeys = [
+            "nplanes", "nchannels", "functional_chan", "align_by_chan", "nimg_init",
+            "batch_size", "max_iterations", "nbinned", "inner_neuropil_radius",
+            "min_neuropil_pixels", "spatial_scale", "do_registration", "anatomical_only"
+        ]
+        self.boolkeys = [
+            "delete_bin", "move_bin", "do_bidiphase", "reg_tif", "reg_tif_chan2",
+            "save_mat", "save_NWB"
+            "combined", "1Preg", "nonrigid", "connected", "roidetect",
+            "neuropil_extract", "spikedetect", "keep_movie_raw", "allow_overlap",
+            "sparse_mode"
+        ]
+        self.stringkeys = ["pretrained_model"]
+        tifkeys = [
+            "nplanes", "nchannels", "functional_chan", "tau", "fs", "do_bidiphase",
+            "bidiphase", "multiplane_parallel", "ignore_flyback"
+        ]
+        outkeys = [
+            "preclassify", "save_mat", "save_NWB", "combined", "reg_tif",
+            "reg_tif_chan2", "aspect", "delete_bin", "move_bin"
+        ]
+        regkeys = [
+            "do_registration", "align_by_chan", "nimg_init", "batch_size",
+            "smooth_sigma", "smooth_sigma_time", "maxregshift", "th_badframes",
+            "keep_movie_raw", "two_step_registration"
+        ]
+        nrkeys = [["nonrigid", "block_size", "snr_thresh", "maxregshiftNR"],
+                  ["1Preg", "spatial_hp_reg", "pre_smooth", "spatial_taper"]]
+        cellkeys = [
+            "roidetect", "sparse_mode", "denoise", "spatial_scale", "threshold_scaling",
+            "max_overlap", "max_iterations", "high_pass", "spatial_hp_detect"
+        ]
+        anatkeys = [
+            "anatomical_only", "diameter", "cellprob_threshold", "flow_threshold",
+            "pretrained_model", "spatial_hp_cp"
+        ]
+        neudeconvkeys = [[
+            "neuropil_extract", "allow_overlap", "inner_neuropil_radius",
+            "min_neuropil_pixels"
+        ], ["soma_crop", "spikedetect", "win_baseline", "sig_baseline", "neucoeff"]]
         keys = [tifkeys, outkeys, regkeys, nrkeys, cellkeys, anatkeys, neudeconvkeys]
-        labels = ['Main settings','Output settings','Registration',['Nonrigid','1P'],'Functional detect', 'Anat detect', ['Extraction/Neuropil','Classify/Deconv']]
-        tooltips = ['each tiff has this many planes in sequence',
-                    'each tiff has this many channels per plane',
-                    'this channel is used to extract functional ROIs (1-based)',
-                    'timescale of sensor in deconvolution (in seconds)',
-                    'sampling rate (per plane)',
-                    'whether or not to compute bidirectional phase offset of recording (from line scanning)',
-                    'set a fixed number (in pixels) for the bidirectional phase offset',
-                    'process each plane with a separate job on a computing cluster',
-                    'ignore flyback planes 0-indexed separated by a comma e.g. "0,10"; "-1" means no planes ignored so all planes processed',
-                    'apply ROI classifier before signal extraction with probability threshold (set to 0 to turn off)',
-                    'save output also as mat file "Fall.mat"',
-                    'save output also as NWB file "ophys.nwb"',
-                    'combine results across planes in separate folder "combined" at end of processing',
-                    'if 1, registered tiffs are saved',
-                    'if 1, registered tiffs of channel 2 (non-functional channel) are saved',
-                    'um/pixels in X / um/pixels in Y (for correct aspect ratio in GUI)',
-                    'if 1, binary file is deleted after processing is complete',
-                    'if 1, and fast_disk is different than save_disk, binary file is moved to save_disk',
-                    "if 1, registration is performed if it wasn't performed already",
-                    'when multi-channel, you can align by non-functional channel (1-based)',
-                    '# of subsampled frames for finding reference image',
-                    'number of frames per batch',
-                    'gaussian smoothing after phase corr: 1.15 good for 2P recordings, recommend 2-5 for 1P recordings',
-                    'gaussian smoothing in time, useful for low SNR data',
-                    'max allowed registration shift, as a fraction of frame max(width and height)',
-                    'this parameter determines which frames to exclude when determining cropped frame size - set it smaller to exclude more frames',
-                    'if 1, unregistered binary is kept in a separate file data_raw.bin',
-                    'run registration twice (useful if data is really noisy), *keep_movie_raw must be 1*',
-                    'whether to use nonrigid registration (splits FOV into blocks of size block_size)',
-                    'block size in number of pixels in Y and X (two numbers separated by a comma)',
-                    'if any nonrigid block is below this threshold, it gets smoothed until above this threshold. 1.0 results in no smoothing',
-                    'maximum *pixel* shift allowed for nonrigid, relative to rigid',
-                    'whether to perform high-pass filtering and tapering for registration (necessary for 1P recordings)',
-                    'window for spatial high-pass filtering before registration',
-                    'whether to smooth before high-pass filtering before registration',
-                    "how much to ignore on edges (important for vignetted windows, for FFT padding do not set BELOW 3*smooth_sigma)",
-                    'if 1, run cell (ROI) detection (either functional or anatomical if anatomical_only > 0)',
-                    'if 1, run sparse_mode cell detection',
-                    'if 1, run PCA denoising on binned movie to improve cell detection',
-                    'choose size of ROIs: 0 = multi-scale; 1 = 6 pixels, 2 = 12, 3 = 24, 4 = 48',
-                    'adjust the automatically determined threshold for finding ROIs by this scalar multiplier',
-                    'ROIs with greater than this overlap as a fraction of total pixels will be discarded',
-                    'maximum number of iterations for ROI detection',
-                    'temporal running mean subtraction with window of size "high_pass" (use low values for 1P)',
-                    'spatial high-pass filter size (used to remove spatially-correlated neuropil)',
-                    'run cellpose to get masks on 1: max_proj / mean_img; 2: mean_img; 3: mean_img enhanced, 4: max_proj',
-                    'input average diameter of ROIs in recording (can give a list e.g. 6,9 if aspect not equal), if set to 0 auto-determination run by Cellpose',
-                    'cellprob_threshold for cellpose',
-                    'flow_threshold for cellpose (throws out masks, if getting too few masks, set to 0)',
-                    'model type string from Cellpose (can be a built-in model or a user model that is added to the Cellpose GUI)',
-                    'high-pass image spatially by a multiple of the diameter (if field is non-uniform, a value of ~2 is recommended',
-                    'whether or not to extract neuropil; if 0, Fneu is set to 0',
-                    'allow shared pixels to be used for fluorescence extraction from overlapping ROIs (otherwise excluded from both ROIs)',
-                    'number of pixels between ROI and neuropil donut',
-                    'minimum number of pixels in the neuropil',
-                    'if 1, crop dendrites for cell classification stats like compactness',
-                    'if 1, run spike detection (deconvolution)',
-                    'window for maximin',
-                    'smoothing constant for gaussian filter',
-                    'neuropil coefficient',
-                    ]
+        labels = [
+            "Main settings", "Output settings", "Registration", ["Nonrigid", "1P"],
+            "Functional detect", "Anat detect",
+            ["Extraction/Neuropil", "Classify/Deconv"]
+        ]
+        tooltips = [
+            "each tiff has this many planes in sequence",
+            "each tiff has this many channels per plane",
+            "this channel is used to extract functional ROIs (1-based)",
+            "timescale of sensor in deconvolution (in seconds)",
+            "sampling rate (per plane)",
+            "whether or not to compute bidirectional phase offset of recording (from line scanning)",
+            "set a fixed number (in pixels) for the bidirectional phase offset",
+            "process each plane with a separate job on a computing cluster",
+            "ignore flyback planes 0-indexed separated by a comma e.g. '0,10'; '-1' means no planes ignored so all planes processed",
+            "apply ROI classifier before signal extraction with probability threshold (set to 0 to turn off)",
+            "save output also as mat file 'Fall.mat'",
+            "save output also as NWB file 'ophys.nwb'",
+            "combine results across planes in separate folder 'combined' at end of processing",
+            "if 1, registered tiffs are saved",
+            "if 1, registered tiffs of channel 2 (non-functional channel) are saved",
+            "um/pixels in X / um/pixels in Y (for correct aspect ratio in GUI)",
+            "if 1, binary file is deleted after processing is complete",
+            "if 1, and fast_disk is different than save_disk, binary file is moved to save_disk",
+            "if 1, registration is performed if it wasn't performed already",
+            "when multi-channel, you can align by non-functional channel (1-based)",
+            "# of subsampled frames for finding reference image",
+            "number of frames per batch",
+            "gaussian smoothing after phase corr: 1.15 good for 2P recordings, recommend 2-5 for 1P recordings",
+            "gaussian smoothing in time, useful for low SNR data",
+            "max allowed registration shift, as a fraction of frame max(width and height)",
+            "this parameter determines which frames to exclude when determining cropped frame size - set it smaller to exclude more frames",
+            "if 1, unregistered binary is kept in a separate file data_raw.bin",
+            "run registration twice (useful if data is really noisy), *keep_movie_raw must be 1*",
+            "whether to use nonrigid registration (splits FOV into blocks of size block_size)",
+            "block size in number of pixels in Y and X (two numbers separated by a comma)",
+            "if any nonrigid block is below this threshold, it gets smoothed until above this threshold. 1.0 results in no smoothing",
+            "maximum *pixel* shift allowed for nonrigid, relative to rigid",
+            "whether to perform high-pass filtering and tapering for registration (necessary for 1P recordings)",
+            "window for spatial high-pass filtering before registration",
+            "whether to smooth before high-pass filtering before registration",
+            "how much to ignore on edges (important for vignetted windows, for FFT padding do not set BELOW 3*smooth_sigma)",
+            "if 1, run cell (ROI) detection (either functional or anatomical if anatomical_only > 0)",
+            "if 1, run sparse_mode cell detection",
+            "if 1, run PCA denoising on binned movie to improve cell detection",
+            "choose size of ROIs: 0 = multi-scale; 1 = 6 pixels, 2 = 12, 3 = 24, 4 = 48",
+            "adjust the automatically determined threshold for finding ROIs by this scalar multiplier",
+            "ROIs with greater than this overlap as a fraction of total pixels will be discarded",
+            "maximum number of iterations for ROI detection",
+            "temporal running mean subtraction with window of size 'high_pass' (use low values for 1P)",
+            "spatial high-pass filter size (used to remove spatially-correlated neuropil)",
+            "run cellpose to get masks on 1: max_proj / mean_img; 2: mean_img; 3: mean_img enhanced, 4: max_proj",
+            "input average diameter of ROIs in recording (can give a list e.g. 6,9 if aspect not equal), if set to 0 auto-determination run by Cellpose",
+            "cellprob_threshold for cellpose",
+            "flow_threshold for cellpose (throws out masks, if getting too few masks, set to 0)",
+            "model type string from Cellpose (can be a built-in model or a user model that is added to the Cellpose GUI)",
+            "high-pass image spatially by a multiple of the diameter (if field is non-uniform, a value of ~2 is recommended",
+            "whether or not to extract neuropil; if 0, Fneu is set to 0",
+            "allow shared pixels to be used for fluorescence extraction from overlapping ROIs (otherwise excluded from both ROIs)",
+            "number of pixels between ROI and neuropil donut",
+            "minimum number of pixels in the neuropil",
+            "if 1, crop dendrites for cell classification stats like compactness",
+            "if 1, run spike detection (deconvolution)",
+            "window for maximin",
+            "smoothing constant for gaussian filter",
+            "neuropil coefficient",
+        ]
 
         bigfont = QtGui.QFont("Arial", 10, QtGui.QFont.Bold)
-        qlabel = QLabel('File paths')
+        qlabel = QLabel("File paths")
         qlabel.setFont(bigfont)
-        self.layout.addWidget(qlabel,0,0,1,1)
-        loadOps = QPushButton('Load ops file')
+        self.layout.addWidget(qlabel, 0, 0, 1, 1)
+        loadOps = QPushButton("Load ops file")
         loadOps.clicked.connect(self.load_ops)
-        saveDef = QPushButton('Save ops as default')
+        saveDef = QPushButton("Save ops as default")
         saveDef.clicked.connect(self.save_default_ops)
-        revertDef = QPushButton('Revert default ops to built-in')
+        revertDef = QPushButton("Revert default ops to built-in")
         revertDef.clicked.connect(self.revert_default_ops)
-        saveOps = QPushButton('Save ops to file')
+        saveOps = QPushButton("Save ops to file")
         saveOps.clicked.connect(self.save_ops)
-        self.layout.addWidget(loadOps,0,4,1,2)
-        self.layout.addWidget(saveDef,1,4,1,2)
-        self.layout.addWidget(revertDef,2,4,1,2)
-        self.layout.addWidget(saveOps,3,4,1,2)
-        self.layout.addWidget(QLabel(''),4,4,1,2)
-        self.layout.addWidget(QLabel('Load example ops'),5,4,1,2)
+        self.layout.addWidget(loadOps, 0, 4, 1, 2)
+        self.layout.addWidget(saveDef, 1, 4, 1, 2)
+        self.layout.addWidget(revertDef, 2, 4, 1, 2)
+        self.layout.addWidget(saveOps, 3, 4, 1, 2)
+        self.layout.addWidget(QLabel(""), 4, 4, 1, 2)
+        self.layout.addWidget(QLabel("Load example ops"), 5, 4, 1, 2)
         for k in range(3):
-            qw = QPushButton('Save ops to file')
+            qw = QPushButton("Save ops to file")
         #saveOps.clicked.connect(self.save_ops)
         self.opsbtns = QButtonGroup(self)
-        opsstr = ['1P imaging', 'dendrites/axons']
-        self.opsname = ['1P', 'dendrite']
+        opsstr = ["1P imaging", "dendrites/axons"]
+        self.opsname = ["1P", "dendrite"]
         for b in range(len(opsstr)):
             btn = OpsButton(b, opsstr[b], self)
             self.opsbtns.addButton(btn, b)
-            self.layout.addWidget(btn, 6+b,4,1,2)
-        l=0
+            self.layout.addWidget(btn, 6 + b, 4, 1, 2)
+        l = 0
         self.keylist = []
         self.editlist = []
-        kk=0
-        wk=0
+        kk = 0
+        wk = 0
         for lkey in keys:
             k = 0
-            kl=0
+            kl = 0
             if type(labels[l]) is list:
                 labs = labels[l]
                 keyl = lkey
@@ -206,80 +241,82 @@ def create_buttons(self):
             for label in labs:
                 qlabel = QLabel(label)
                 qlabel.setFont(bigfont)
-                self.layout.addWidget(qlabel,k*2,2*(l+4),1,2)
-                k+=1
+                self.layout.addWidget(qlabel, k * 2, 2 * (l + 4), 1, 2)
+                k += 1
                 for key in keyl[kl]:
                     lops = 1
-                    if self.ops[key] or (self.ops[key] == 0) or len(self.ops[key])==0:
-                        qedit = LineEdit(wk,key,self)
+                    if self.ops[key] or (self.ops[key] == 0) or len(self.ops[key]) == 0:
+                        qedit = LineEdit(wk, key, self)
                         qlabel = QLabel(key)
                         qlabel.setToolTip(tooltips[kk])
                         qedit.set_text(self.ops)
                         qedit.setToolTip(tooltips[kk])
                         qedit.setFixedWidth(90)
-                        self.layout.addWidget(qlabel,k*2-1,2*(l+4),1,2)
-                        self.layout.addWidget(qedit,k*2,2*(l+4),1,2)
+                        self.layout.addWidget(qlabel, k * 2 - 1, 2 * (l + 4), 1, 2)
+                        self.layout.addWidget(qedit, k * 2, 2 * (l + 4), 1, 2)
                         self.keylist.append(key)
                         self.editlist.append(qedit)
-                        wk+=1
-                    k+=1
-                    kk+=1
-                kl+=1
-            l+=1
+                        wk += 1
+                    k += 1
+                    kk += 1
+                kl += 1
+            l += 1
 
         # data_path
-        key = 'input_format'
+        key = "input_format"
         qlabel = QLabel(key)
         qlabel.setFont(bigfont)
-        qlabel.setToolTip('File format (selects which parser to use)')
-        self.layout.addWidget(qlabel,1,0,1,1)
+        qlabel.setToolTip("File format (selects which parser to use)")
+        self.layout.addWidget(qlabel, 1, 0, 1, 1)
         self.inputformat = QComboBox()
-        [self.inputformat.addItem(f) for f in ['tif','bruker','sbx', 'h5','mesoscan','haus', 'nd2']]
+        [
+            self.inputformat.addItem(f)
+            for f in ["tif", "bruker", "sbx", "h5", "mesoscan", "haus", "nd2"]
+        ]
         self.inputformat.currentTextChanged.connect(self.parse_inputformat)
-        self.layout.addWidget(self.inputformat,2,0,1,1)
+        self.layout.addWidget(self.inputformat, 2, 0, 1, 1)
 
-        key = 'look_one_level_down'
+        key = "look_one_level_down"
         qlabel = QLabel(key)
-        qlabel.setToolTip('whether to look in all subfolders when searching for files')
-        self.layout.addWidget(qlabel,3,0,1,1)
-        qedit = LineEdit(wk,key,self)
+        qlabel.setToolTip("whether to look in all subfolders when searching for files")
+        self.layout.addWidget(qlabel, 3, 0, 1, 1)
+        qedit = LineEdit(wk, key, self)
         qedit.set_text(self.ops)
         qedit.setFixedWidth(95)
-        self.layout.addWidget(qedit,4,0,1,1)
+        self.layout.addWidget(qedit, 4, 0, 1, 1)
         self.keylist.append(key)
         self.editlist.append(qedit)
 
-        cw=4
-        self.btiff = QPushButton('Add directory to data_path')
+        cw = 4
+        self.btiff = QPushButton("Add directory to data_path")
         self.btiff.clicked.connect(self.get_folders)
-        self.layout.addWidget(self.btiff,5,0,1,cw)
-        qlabel = QLabel('data_path')
+        self.layout.addWidget(self.btiff, 5, 0, 1, cw)
+        qlabel = QLabel("data_path")
         qlabel.setFont(bigfont)
-        self.layout.addWidget(qlabel,6,0,1,1)
+        self.layout.addWidget(qlabel, 6, 0, 1, 1)
         self.qdata = []
         for n in range(9):
-            self.qdata.append(QLabel(''))
-            self.layout.addWidget(self.qdata[n],
-                                  n+7,0,1,cw)
+            self.qdata.append(QLabel(""))
+            self.layout.addWidget(self.qdata[n], n + 7, 0, 1, cw)
 
-        self.bsave = QPushButton('Add save_path (default is 1st data_path)')
+        self.bsave = QPushButton("Add save_path (default is 1st data_path)")
         self.bsave.clicked.connect(self.save_folder)
-        self.layout.addWidget(self.bsave,16,0,1,cw)
-        self.savelabel = QLabel('')
-        self.layout.addWidget(self.savelabel,17,0,1,cw)
+        self.layout.addWidget(self.bsave, 16, 0, 1, cw)
+        self.savelabel = QLabel("")
+        self.layout.addWidget(self.savelabel, 17, 0, 1, cw)
         # fast_disk
-        self.bbin = QPushButton('Add fast_disk (default is save_path)')
+        self.bbin = QPushButton("Add fast_disk (default is save_path)")
         self.bbin.clicked.connect(self.bin_folder)
-        self.layout.addWidget(self.bbin,18,0,1,cw)
-        self.binlabel = QLabel('')
-        self.layout.addWidget(self.binlabel,19,0,1,cw)
-        self.runButton = QPushButton('RUN SUITE2P')
+        self.layout.addWidget(self.bbin, 18, 0, 1, cw)
+        self.binlabel = QLabel("")
+        self.layout.addWidget(self.binlabel, 19, 0, 1, cw)
+        self.runButton = QPushButton("RUN SUITE2P")
         self.runButton.clicked.connect(self.run_S2P)
         n0 = 22
-        self.layout.addWidget(self.runButton,n0,0,1,1)
+        self.layout.addWidget(self.runButton, n0, 0, 1, 1)
         self.runButton.setEnabled(False)
         self.textEdit = QTextEdit()
-        self.layout.addWidget(self.textEdit, n0+1,0,30,2*l)
+        self.layout.addWidget(self.textEdit, n0 + 1, 0, 30, 2 * l)
         self.textEdit.setFixedHeight(300)
         self.process = QtCore.QProcess(self)
         self.process.readyReadStandardOutput.connect(self.stdout_write)
@@ -288,34 +325,33 @@ def create_buttons(self):
         self.process.started.connect(self.started)
         self.process.finished.connect(self.finished)
         # stop process
-        self.stopButton = QPushButton('STOP')
+        self.stopButton = QPushButton("STOP")
         self.stopButton.setEnabled(False)
-        self.layout.addWidget(self.stopButton, n0,1,1,1)
+        self.layout.addWidget(self.stopButton, n0, 1, 1, 1)
         self.stopButton.clicked.connect(self.stop)
         # cleanup button
-        self.cleanButton = QPushButton('Add a clean-up *.py')
-        self.cleanButton.setToolTip('will run at end of processing')
+        self.cleanButton = QPushButton("Add a clean-up *.py")
+        self.cleanButton.setToolTip("will run at end of processing")
         self.cleanButton.setEnabled(True)
-        self.layout.addWidget(self.cleanButton, n0,2,1,2)
+        self.layout.addWidget(self.cleanButton, n0, 2, 1, 2)
         self.cleanup = False
         self.cleanButton.clicked.connect(self.clean_script)
-        self.cleanLabel = QLabel('')
-        self.layout.addWidget(self.cleanLabel,n0,4,1,12)
+        self.cleanLabel = QLabel("")
+        self.layout.addWidget(self.cleanLabel, n0, 4, 1, 12)
         #n0+=1
-        self.listOps = QPushButton('save settings and\n add more (batch)')
+        self.listOps = QPushButton("save settings and\n add more (batch)")
         self.listOps.clicked.connect(self.add_batch)
-        self.layout.addWidget(self.listOps,n0,12,1,2)
+        self.layout.addWidget(self.listOps, n0, 12, 1, 2)
         self.listOps.setEnabled(False)
-        self.removeOps = QPushButton('remove last added')
+        self.removeOps = QPushButton("remove last added")
         self.removeOps.clicked.connect(self.remove_ops)
-        self.layout.addWidget(self.removeOps,n0,14,1,2)
+        self.layout.addWidget(self.removeOps, n0, 14, 1, 2)
         self.removeOps.setEnabled(False)
         self.odata = []
         self.n_batch = 15
         for n in range(self.n_batch):
-            self.odata.append(QLabel(''))
-            self.layout.addWidget(self.odata[n],
-                                  n0+1+n,12,1,4)
+            self.odata.append(QLabel(""))
+            self.layout.addWidget(self.odata[n], n0 + 1 + n, 12, 1, 4)
 
     def remove_ops(self):
         L = len(self.opslist)
@@ -324,9 +360,9 @@ def remove_ops(self):
             self.opslist = []
             self.removeOps.setEnabled(False)
         else:
-            del self.opslist[L-1]
-        self.odata[L-1].setText('')
-        self.odata[L-1].setToolTip('')
+            del self.opslist[L - 1]
+        self.odata[L - 1].setText("")
+        self.odata[L - 1].setToolTip("")
         self.f = 0
 
     def add_batch(self):
@@ -341,9 +377,9 @@ def add_batch(self):
         self.save_path = []
         self.fast_disk = []
         for n in range(self.n_batch):
-            self.qdata[n].setText('')
-        self.savelabel.setText('')
-        self.binlabel.setText('')
+            self.qdata[n].setText("")
+        self.savelabel.setText("")
+        self.binlabel.setText("")
 
         # clear all ops
         # self.reset_ops()
@@ -361,53 +397,55 @@ def add_ops(self):
         self.f = 0
         self.compile_ops_db()
         L = len(self.opslist)
-        np.save(os.path.join(self.ops_path, 'ops%d.npy'%L), self.ops)
-        np.save(os.path.join(self.ops_path, 'db%d.npy'%L), self.db)
-        self.opslist.append('ops%d.npy'%L)
-        if hasattr(self, 'h5_key') and len(self.h5_key) > 0:
-            self.db['h5py_key'] = self.h5_key
+        np.save(os.path.join(self.ops_path, "ops%d.npy" % L), self.ops)
+        np.save(os.path.join(self.ops_path, "db%d.npy" % L), self.db)
+        self.opslist.append("ops%d.npy" % L)
+        if hasattr(self, "h5_key") and len(self.h5_key) > 0:
+            self.db["h5py_key"] = self.h5_key
 
     def compile_ops_db(self):
-        for k,key in enumerate(self.keylist):
-            self.ops[key] = self.editlist[k].get_text(self.intkeys, self.boolkeys, self.stringkeys)
+        for k, key in enumerate(self.keylist):
+            self.ops[key] = self.editlist[k].get_text(self.intkeys, self.boolkeys,
+                                                      self.stringkeys)
         self.db = {}
-        self.db['data_path'] = self.data_path
-        self.db['subfolders'] = []
+        self.db["data_path"] = self.data_path
+        self.db["subfolders"] = []
         self.datastr = self.data_path[0]
 
         # add data type specific keys
-        if hasattr(self, 'h5_key') and len(self.h5_key) > 0:
-            self.db['h5py_key'] = self.h5_key
-        elif self.inputformat.currentText() == 'sbx':
-            self.db['sbx_ndeadcols'] = -1
+        if hasattr(self, "h5_key") and len(self.h5_key) > 0:
+            self.db["h5py_key"] = self.h5_key
+        elif self.inputformat.currentText() == "sbx":
+            self.db["sbx_ndeadcols"] = -1
 
         # add save_path0 and fast_disk
-        if len(self.save_path)==0:
-            self.save_path = self.db['data_path'][0]
-        self.db['save_path0'] = self.save_path
-        if len(self.fast_disk)==0:
+        if len(self.save_path) == 0:
+            self.save_path = self.db["data_path"][0]
+        self.db["save_path0"] = self.save_path
+        if len(self.fast_disk) == 0:
             self.fast_disk = self.save_path
-        self.db['fast_disk'] = self.fast_disk
-        self.db['input_format'] = self.inputformat.currentText()
+        self.db["fast_disk"] = self.fast_disk
+        self.db["input_format"] = self.inputformat.currentText()
 
     def run_S2P(self):
-        if len(self.opslist)==0:
+        if len(self.opslist) == 0:
             self.add_ops()
         # pre-download model
-        pretrained_model_string = self.ops.get('pretrained_model', 'cyto')
-        pretrained_model_string = pretrained_model_string if pretrained_model_string is not None else 'cyto'
+        pretrained_model_string = self.ops.get("pretrained_model", "cyto")
+        pretrained_model_string = pretrained_model_string if pretrained_model_string is not None else "cyto"
         pretrained_model_path = model_path(pretrained_model_string, 0, True)
         self.finish = True
         self.error = False
-        ops_file = os.path.join(self.ops_path, 'ops.npy')
-        db_file = os.path.join(self.ops_path, 'db.npy')
-        shutil.copy(os.path.join(self.ops_path, 'ops%d.npy'%self.f), ops_file)
-        shutil.copy(os.path.join(self.ops_path, 'db%d.npy'%self.f), db_file)
+        ops_file = os.path.join(self.ops_path, "ops.npy")
+        db_file = os.path.join(self.ops_path, "db.npy")
+        shutil.copy(os.path.join(self.ops_path, "ops%d.npy" % self.f), ops_file)
+        shutil.copy(os.path.join(self.ops_path, "db%d.npy" % self.f), db_file)
         self.db = np.load(db_file, allow_pickle=True).item()
-        print('Running suite2p!')
-        print('starting process')
+        print("Running suite2p!")
+        print("starting process")
         print(self.db)
-        self.process.start('python -u -W ignore -m suite2p --ops "%s" --db "%s"'%(ops_file, db_file))
+        self.process.start('python -u -W ignore -m suite2p --ops "%s" --db "%s"' %
+                           (ops_file, db_file))
 
     def stop(self):
         self.finish = False
@@ -418,49 +456,51 @@ def started(self):
         self.runButton.setEnabled(False)
         self.stopButton.setEnabled(True)
         self.cleanButton.setEnabled(False)
-        save_folder = os.path.join(self.db['save_path0'], 'suite2p/')
+        save_folder = os.path.join(self.db["save_path0"], "suite2p/")
         if not os.path.isdir(save_folder):
             os.makedirs(save_folder)
-        self.logfile = open(os.path.join(save_folder, 'run.log'), 'a')
+        self.logfile = open(os.path.join(save_folder, "run.log"), "a")
         dstring = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
-        self.logfile.write('\n >>>>> started run at %s'%dstring)
+        self.logfile.write("\n >>>>> started run at %s" % dstring)
 
     def finished(self):
         self.logfile.close()
         self.runButton.setEnabled(True)
         self.stopButton.setEnabled(False)
         cursor = self.textEdit.textCursor()
-        cursor.movePosition(cursor.End)    
+        cursor.movePosition(cursor.End)
         if self.finish and not self.error:
             self.cleanButton.setEnabled(True)
-            if len(self.opslist)==1:
-                self.parent.fname = os.path.join(self.db['save_path0'], 'suite2p', 'plane0','stat.npy')
+            if len(self.opslist) == 1:
+                self.parent.fname = os.path.join(self.db["save_path0"], "suite2p",
+                                                 "plane0", "stat.npy")
                 if os.path.exists(self.parent.fname):
-                    cursor.insertText('Opening in GUI (can close this window)\n')
+                    cursor.insertText("Opening in GUI (can close this window)\n")
                     io.load_proc(self.parent)
                 else:
-                    cursor.insertText('not opening plane in GUI (no ROIs)\n')
+                    cursor.insertText("not opening plane in GUI (no ROIs)\n")
             else:
-                cursor.insertText('BATCH MODE: %d more recordings remaining \n'%(len(self.opslist)-self.f-1))
+                cursor.insertText("BATCH MODE: %d more recordings remaining \n" %
+                                  (len(self.opslist) - self.f - 1))
                 self.f += 1
                 if self.f < len(self.opslist):
                     self.run_S2P()
         elif not self.error:
-            cursor.insertText('Interrupted by user (not finished)\n')
+            cursor.insertText("Interrupted by user (not finished)\n")
         else:
-            cursor.insertText('Interrupted by error (not finished)\n')
+            cursor.insertText("Interrupted by error (not finished)\n")
 
-        # remove current ops from processing list        
-        if len(self.opslist)==1:
+        # remove current ops from processing list
+        if len(self.opslist) == 1:
             del self.opslist[0]
-    
+
     def save_ops(self):
-        name = QFileDialog.getSaveFileName(self,'Ops name (*.npy)')
+        name = QFileDialog.getSaveFileName(self, "Ops name (*.npy)")
         name = name[0]
         self.save_text()
         if name:
             np.save(name, self.ops)
-            print('saved current settings to %s'%(name))
+            print("saved current settings to %s" % (name))
 
     def save_default_ops(self):
         name = self.opsfile
@@ -469,7 +509,7 @@ def save_default_ops(self):
         self.save_text()
         np.save(name, self.ops)
         self.ops = ops
-        print('saved current settings in GUI as default ops')
+        print("saved current settings in GUI as default ops")
 
     def revert_default_ops(self):
         name = self.opsfile
@@ -477,110 +517,111 @@ def revert_default_ops(self):
         self.ops = default_ops()
         np.save(name, self.ops)
         self.load_ops(name)
-        print('reverted default ops to built-in ops')
+        print("reverted default ops to built-in ops")
 
     def save_text(self):
         for k in range(len(self.editlist)):
             key = self.keylist[k]
-            self.ops[key] = self.editlist[k].get_text(self.intkeys, self.boolkeys, self.stringkeys)
+            self.ops[key] = self.editlist[k].get_text(self.intkeys, self.boolkeys,
+                                                      self.stringkeys)
 
     def load_ops(self, name=None):
-        print('loading ops')
-        if not (isinstance(name, str) and len(name)>0):
-            name = QFileDialog.getOpenFileName(self, 'Open ops file (npy or json)')
+        print("loading ops")
+        if not (isinstance(name, str) and len(name) > 0):
+            name = QFileDialog.getOpenFileName(self, "Open ops file (npy or json)")
             name = name[0]
-        
+
         if len(name) > 0:
             ext = os.path.splitext(name)[1]
             try:
-                if ext == '.npy':
+                if ext == ".npy":
                     ops = np.load(name, allow_pickle=True).item()
-                elif ext == '.json':
-                    with open(name, 'r') as f:
+                elif ext == ".json":
+                    with open(name, "r") as f:
                         ops = json.load(f)
                 ops0 = default_ops()
                 ops = {**ops0, **ops}
                 for key in ops:
-                    if key!='data_path' and key!='save_path' and key!='fast_disk' and key!='cleanup' and key!='save_path0' and key!='h5py':
+                    if key != "data_path" and key != "save_path" and key != "fast_disk" and key != "cleanup" and key != "save_path0" and key != "h5py":
                         if key in self.keylist:
                             self.editlist[self.keylist.index(key)].set_text(ops)
                         self.ops[key] = ops[key]
-                if not 'input_format' in self.ops.keys():
-                    self.ops['input_format'] = 'tif'
-                if 'data_path' in ops and len(ops['data_path'])>0:
-                    self.data_path = ops['data_path']
+                if not "input_format" in self.ops.keys():
+                    self.ops["input_format"] = "tif"
+                if "data_path" in ops and len(ops["data_path"]) > 0:
+                    self.data_path = ops["data_path"]
                     for n in range(9):
-                        if n<len(self.data_path):
+                        if n < len(self.data_path):
                             self.qdata[n].setText(self.data_path[n])
                         else:
-                            self.qdata[n].setText('')
+                            self.qdata[n].setText("")
                     self.runButton.setEnabled(True)
                     self.btiff.setEnabled(True)
                     self.listOps.setEnabled(True)
-                if 'h5py_key' in ops and len(ops['h5py_key'])>0:
-                    self.h5_key = ops['h5py_key']
-                self.inputformat.currentTextChanged.connect(lambda x:x)
-                self.inputformat.setCurrentText(self.ops['input_format'])
+                if "h5py_key" in ops and len(ops["h5py_key"]) > 0:
+                    self.h5_key = ops["h5py_key"]
+                self.inputformat.currentTextChanged.connect(lambda x: x)
+                self.inputformat.setCurrentText(self.ops["input_format"])
                 self.inputformat.currentTextChanged.connect(self.parse_inputformat)
-                if self.ops['input_format'] == 'sbx':
+                if self.ops["input_format"] == "sbx":
                     self.runButton.setEnabled(True)
                     self.btiff.setEnabled(False)
                     self.listOps.setEnabled(True)
 
-                if 'save_path0' in ops and len(ops['save_path0'])>0:
-                    self.save_path = ops['save_path0']
+                if "save_path0" in ops and len(ops["save_path0"]) > 0:
+                    self.save_path = ops["save_path0"]
                     self.savelabel.setText(self.save_path)
-                if 'fast_disk' in ops and len(ops['fast_disk'])>0:
-                    self.fast_disk = ops['fast_disk']
+                if "fast_disk" in ops and len(ops["fast_disk"]) > 0:
+                    self.fast_disk = ops["fast_disk"]
                     self.binlabel.setText(self.fast_disk)
-                if 'clean_script' in ops and len(ops['clean_script'])>0:
-                    self.ops['clean_script'] = ops['clean_script']
-                    self.cleanLabel.setText(ops['clean_script'])
+                if "clean_script" in ops and len(ops["clean_script"]) > 0:
+                    self.ops["clean_script"] = ops["clean_script"]
+                    self.cleanLabel.setText(ops["clean_script"])
 
             except Exception as e:
-                print('could not load ops file')
+                print("could not load ops file")
                 print(e)
 
     def load_db(self):
-        print('loading db')
+        print("loading db")
 
     def stdout_write(self):
         cursor = self.textEdit.textCursor()
         cursor.movePosition(cursor.End)
-        output = str(self.process.readAllStandardOutput(), 'utf-8')
+        output = str(self.process.readAllStandardOutput(), "utf-8")
         cursor.insertText(output)
         self.textEdit.ensureCursorVisible()
-        #self.logfile = open(os.path.join(self.save_path, 'suite2p/run.log'), 'a')
+        #self.logfile = open(os.path.join(self.save_path, "suite2p/run.log"), "a")
         self.logfile.write(output)
         #self.logfile.close()
 
     def stderr_write(self):
         cursor = self.textEdit.textCursor()
         cursor.movePosition(cursor.End)
-        cursor.insertText('>>>ERROR<<<\n')
-        output = str(self.process.readAllStandardError(), 'utf-8')
+        cursor.insertText(">>>ERROR<<<\n")
+        output = str(self.process.readAllStandardError(), "utf-8")
         cursor.insertText(output)
         self.textEdit.ensureCursorVisible()
         self.error = True
-        #self.logfile = open(os.path.join(self.save_path, 'suite2p/run.log'), 'a')
-        self.logfile.write('>>>ERROR<<<\n')
+        #self.logfile = open(os.path.join(self.save_path, "suite2p/run.log"), "a")
+        self.logfile.write(">>>ERROR<<<\n")
         self.logfile.write(output)
 
     def clean_script(self):
-        name = QFileDialog.getOpenFileName(self, 'Open clean up file',filter='*.py')
+        name = QFileDialog.getOpenFileName(self, "Open clean up file", filter="*.py")
         name = name[0]
         if name:
             self.cleanup = True
             self.cleanScript = name
             self.cleanLabel.setText(name)
-            self.ops['clean_script'] = name
+            self.ops["clean_script"] = name
 
     def get_folders(self):
         name = QFileDialog.getExistingDirectory(self, "Add directory to data path")
-        if len(name)>0:
+        if len(name) > 0:
             self.data_path.append(name)
-            self.qdata[len(self.data_path)-1].setText(name)
-            self.qdata[len(self.data_path)-1].setToolTip(name)
+            self.qdata[len(self.data_path) - 1].setText(name)
+            self.qdata[len(self.data_path) - 1].setToolTip(name)
             self.runButton.setEnabled(True)
             self.listOps.setEnabled(True)
             #self.loadDb.setEnabled(False)
@@ -592,26 +633,24 @@ def get_h5py(self):
         if result:
             self.h5_key = TC.h5_key
         else:
-            self.h5_key = 'data'
+            self.h5_key = "data"
 
     def parse_inputformat(self):
         inputformat = self.inputformat.currentText()
-        print('Input format: ' + inputformat)
-        if inputformat == 'h5':
+        print("Input format: " + inputformat)
+        if inputformat == "h5":
             # replace functionality of "old" button
             self.get_h5py()
         else:
             pass
 
-
     def save_folder(self):
         name = QFileDialog.getExistingDirectory(self, "Save folder for data")
-        if len(name)>0:
+        if len(name) > 0:
             self.save_path = name
             self.savelabel.setText(name)
             self.savelabel.setToolTip(name)
 
-
     def bin_folder(self):
         name = QFileDialog.getExistingDirectory(self, "Folder for binary file")
         self.fast_disk = name
@@ -620,24 +659,25 @@ def bin_folder(self):
 
 
 class LineEdit(QLineEdit):
-    def __init__(self,k,key,parent=None):
-        super(LineEdit,self).__init__(parent)
+
+    def __init__(self, k, key, parent=None):
+        super(LineEdit, self).__init__(parent)
         self.key = key
         #self.textEdited.connect(lambda: self.edit_changed(parent.ops, k))
 
-    def get_text(self,intkeys,boolkeys,stringkeys):
+    def get_text(self, intkeys, boolkeys, stringkeys):
         key = self.key
-        if key=='diameter' or key=='block_size':
-            diams = self.text().replace(' ','').split(',')
-            if len(diams)>1:
+        if key == "diameter" or key == "block_size":
+            diams = self.text().replace(" ", "").split(",")
+            if len(diams) > 1:
                 okey = [int(diams[0]), int(diams[1])]
             else:
                 okey = int(diams[0])
-        elif key=='ignore_flyback':
-            okey = self.text().replace(' ','').split(',')
+        elif key == "ignore_flyback":
+            okey = self.text().replace(" ", "").split(",")
             for i in range(len(okey)):
                 okey[i] = int(okey[i])
-            if len(okey)==1 and okey[0]==-1:
+            if len(okey) == 1 and okey[0] == -1:
                 okey = []
         else:
             if key in intkeys:
@@ -650,24 +690,24 @@ def get_text(self,intkeys,boolkeys,stringkeys):
                 okey = float(self.text())
         return okey
 
-    def set_text(self,ops):
+    def set_text(self, ops):
         key = self.key
-        if key=='diameter' or key=='block_size':
-            if (type(ops[key]) is not int) and (len(ops[key])>1):
-                dstr = str(int(ops[key][0])) + ', ' + str(int(ops[key][1]))
+        if key == "diameter" or key == "block_size":
+            if (type(ops[key]) is not int) and (len(ops[key]) > 1):
+                dstr = str(int(ops[key][0])) + ", " + str(int(ops[key][1]))
             else:
                 dstr = str(int(ops[key]))
-        elif key=='ignore_flyback':
+        elif key == "ignore_flyback":
             if not isinstance(ops[key], (list, np.ndarray)):
                 ops[key] = [ops[key]]
-            if len(ops[key])==0:
-                dstr = '-1'
+            if len(ops[key]) == 0:
+                dstr = "-1"
             else:
-                dstr = ''
+                dstr = ""
                 for i in ops[key]:
                     dstr += str(int(i))
-                    if i<len(ops[key])-1:
-                        dstr+=', '
+                    if i < len(ops[key]) - 1:
+                        dstr += ", "
         else:
             if type(ops[key]) is not bool:
                 dstr = str(ops[key])
@@ -675,28 +715,32 @@ def set_text(self,ops):
                 dstr = str(int(ops[key]))
         self.setText(dstr)
 
+
 class OpsButton(QPushButton):
+
     def __init__(self, bid, Text, parent=None):
-        super(OpsButton,self).__init__(parent)
+        super(OpsButton, self).__init__(parent)
         self.setText(Text)
         self.clicked.connect(lambda: self.press(parent, bid))
         self.show()
+
     def press(self, parent, bid):
         try:
             opsdef = os.path.join(os.path.abspath(os.path.dirname(__file__)),
-                                              '../ops/ops_%s.npy'%parent.opsname[bid])
+                                  "../ops/ops_%s.npy" % parent.opsname[bid])
             ops = np.load(opsdef, allow_pickle=True).item()
             for key in ops:
                 if key in parent.keylist:
                     parent.editlist[parent.keylist.index(key)].set_text(ops)
                     parent.ops[key] = ops[key]
         except Exception as e:
-            print('could not load ops file')
+            print("could not load ops file")
             print(e)
 
 
 # custom vertical label
 class VerticalLabel(QWidget):
+
     def __init__(self, text=None):
         super(self.__class__, self).__init__()
         self.text = text
diff --git a/suite2p/gui/traces.py b/suite2p/gui/traces.py
index f17a29520..df45be203 100644
--- a/suite2p/gui/traces.py
+++ b/suite2p/gui/traces.py
@@ -5,13 +5,13 @@
 
 def plot_trace(parent):
     parent.p3.clear()
-    ax = parent.p3.getAxis('left')
-    if len(parent.imerge)==1:
+    ax = parent.p3.getAxis("left")
+    if len(parent.imerge) == 1:
         n = parent.imerge[0]
-        f = parent.Fcell[n,:]
-        fneu = parent.Fneu[n,:]
-        sp = parent.Spks[n,:]
-        if np.ptp(fneu)==0:
+        f = parent.Fcell[n, :]
+        fneu = parent.Fneu[n, :]
+        sp = parent.Spks[n, :]
+        if np.ptp(fneu) == 0:
             fmax = f.max()
             fmin = f.min()
         else:
@@ -23,60 +23,61 @@ def plot_trace(parent):
         sp *= fmax - fmin
         #sp += fmin*0.95
         if parent.tracesOn:
-            parent.p3.plot(parent.trange,f,pen='c')
+            parent.p3.plot(parent.trange, f, pen="c")
         if parent.neuropilOn:
-            parent.p3.plot(parent.trange,fneu,pen='r')
+            parent.p3.plot(parent.trange, fneu, pen="r")
         if parent.deconvOn:
-            parent.p3.plot(parent.trange,(sp+fmin),pen=(255,255,255,150))
-        parent.fmin= fmin
-        parent.fmax=fmax
+            parent.p3.plot(parent.trange, (sp + fmin), pen=(255, 255, 255, 150))
+        parent.fmin = fmin
+        parent.fmax = fmax
         ax.setTicks(None)
     else:
         nmax = int(parent.ncedit.text())
-        kspace = 1.0/parent.sc
+        kspace = 1.0 / parent.sc
         ttick = list()
-        pmerge = parent.imerge[:np.minimum(len(parent.imerge),nmax)]
-        k=len(pmerge)-1
+        pmerge = parent.imerge[:np.minimum(len(parent.imerge), nmax)]
+        k = len(pmerge) - 1
         i = parent.activityMode
         favg = np.zeros((parent.Fcell.shape[1],))
         for n in pmerge[::-1]:
-            if i==0:
-                f = parent.Fcell[n,:]
-            elif i==1:
-                f = parent.Fneu[n,:]
-            elif i==2:
-                f = parent.Fcell[n,:] - 0.7*parent.Fneu[n,:]
+            if i == 0:
+                f = parent.Fcell[n, :]
+            elif i == 1:
+                f = parent.Fneu[n, :]
+            elif i == 2:
+                f = parent.Fcell[n, :] - 0.7 * parent.Fneu[n, :]
             else:
-                f = parent.Spks[n,:]
+                f = parent.Spks[n, :]
             favg += f.flatten()
             fmax = f.max()
             fmin = f.min()
             f = (f - fmin) / (fmax - fmin)
-            rgb = parent.colors['cols'][0][n,:]
-            parent.p3.plot(parent.trange,f+k*kspace,pen=rgb)
-            ttick.append((k*kspace+f.mean(), str(n)))
-            k-=1
-        bsc = len(pmerge)/25 + 1
+            rgb = parent.colors["cols"][0][n, :]
+            parent.p3.plot(parent.trange, f + k * kspace, pen=rgb)
+            ttick.append((k * kspace + f.mean(), str(n)))
+            k -= 1
+        bsc = len(pmerge) / 25 + 1
         favg -= favg.min()
         favg /= favg.max()
         # at bottom plot behavior and avg trace
-        parent.fmin=0
-        if len(pmerge)>5:
-            parent.p3.plot(parent.trange,-1*bsc+favg*bsc,pen=(140,140,140))
-            parent.fmin=-1*bsc
+        parent.fmin = 0
+        if len(pmerge) > 5:
+            parent.p3.plot(parent.trange, -1 * bsc + favg * bsc, pen=(140, 140, 140))
+            parent.fmin = -1 * bsc
         if parent.bloaded:
-            parent.p3.plot(parent.trange,-1*bsc+favg*bsc,pen=(140,140,140))
-            parent.p3.plot(parent.beh_time,-1*bsc+parent.beh*bsc,pen='w')
-            parent.fmin=-1*bsc
-            #parent.traceLabel[0].setText("<font color='gray'>mean activity</font>")
+            parent.p3.plot(parent.trange, -1 * bsc + favg * bsc, pen=(140, 140, 140))
+            parent.p3.plot(parent.beh_time, -1 * bsc + parent.beh * bsc, pen="w")
+            parent.fmin = -1 * bsc
+            #parent.traceLabel[0].setText("<font color="gray">mean activity</font>")
             #parent.traceLabel[1].setText("<font color='white'>1D variable</font>")
             #parent.traceLabel[2].setText("")
-            #ck.append((-0.5*bsc,'1D var'))
+            #ck.append((-0.5*bsc,"1D var"))
 
-        parent.fmax=(len(pmerge)-1)*kspace + 1
+        parent.fmax = (len(pmerge) - 1) * kspace + 1
         ax.setTicks([ttick])
     #parent.p3.setXRange(0,parent.Fcell.shape[1])
-    parent.p3.setYRange(parent.fmin,parent.fmax)
+    parent.p3.setYRange(parent.fmin, parent.fmax)
+
 
 def make_buttons(parent, b0):
     # combo box to decide what kind of activity to view
@@ -85,7 +86,7 @@ def make_buttons(parent, b0):
     parent.l0.addWidget(qlabel, b0, 0, 1, 1)
     parent.comboBox = QComboBox(parent)
     parent.comboBox.setFixedWidth(100)
-    parent.l0.addWidget(parent.comboBox, b0+1, 0, 1, 1)
+    parent.l0.addWidget(parent.comboBox, b0 + 1, 0, 1, 1)
     parent.comboBox.addItem("F")
     parent.comboBox.addItem("Fneu")
     parent.comboBox.addItem("F - 0.7*Fneu")
@@ -107,11 +108,7 @@ def make_buttons(parent, b0):
         btn.setMaximumWidth(22)
         btn.setFont(QtGui.QFont("Arial", 11, QtGui.QFont.Bold))
         btn.setStyleSheet(parent.styleUnpressed)
-        parent.l0.addWidget(
-            btn,
-            b0+b, 1, 1, 1,
-            QtCore.Qt.AlignRight
-        )
+        parent.l0.addWidget(btn, b0 + b, 1, 1, 1, QtCore.Qt.AlignRight)
         b += 1
 
     parent.pmButtons = [QPushButton(" +"), QPushButton(" -")]
@@ -128,12 +125,12 @@ def make_buttons(parent, b0):
     # choose max # of cells plotted
     parent.l0.addWidget(
         QLabel("<font color='white'>max # plotted:</font>"),
-        b0+2,
+        b0 + 2,
         0,
         1,
         1,
     )
-    b0+=3
+    b0 += 3
     parent.ncedit = QLineEdit(parent)
     parent.ncedit.setValidator(QtGui.QIntValidator(0, 400))
     parent.ncedit.setText("40")
@@ -149,10 +146,7 @@ def make_buttons(parent, b0):
     parent.checkBoxd.toggled.connect(lambda: deconv_on(parent))
     parent.deconvOn = True
     parent.checkBoxd.toggle()
-    parent.l0.addWidget(parent.checkBoxd,
-    b0,
-    3,
-    1, 2)
+    parent.l0.addWidget(parent.checkBoxd, b0, 3, 1, 2)
     # neuropil CHECKBOX
     parent.l0.setVerticalSpacing(4)
     parent.checkBoxn = QCheckBox("neuropil [B]")
@@ -160,9 +154,7 @@ def make_buttons(parent, b0):
     parent.checkBoxn.toggled.connect(lambda: neuropil_on(parent))
     parent.neuropilOn = True
     parent.checkBoxn.toggle()
-    parent.l0.addWidget(parent.checkBoxn,
-    b0,5,
-    1, 2)
+    parent.l0.addWidget(parent.checkBoxn, b0, 5, 1, 2)
     # traces CHECKBOX
     parent.l0.setVerticalSpacing(4)
     parent.checkBoxt = QCheckBox("raw fluor [V]")
@@ -170,40 +162,44 @@ def make_buttons(parent, b0):
     parent.checkBoxt.toggled.connect(lambda: traces_on(parent))
     parent.tracesOn = True
     parent.checkBoxt.toggle()
-    parent.l0.addWidget(parent.checkBoxt,
-    b0,7,
-    1, 2)
+    parent.l0.addWidget(parent.checkBoxt, b0, 7, 1, 2)
     return b0
 
+
 def expand_scale(parent):
     parent.sc += 0.5
     parent.sc = np.minimum(10, parent.sc)
     plot_trace(parent)
     parent.show()
 
+
 def collapse_scale(parent):
     parent.sc -= 0.5
     parent.sc = np.maximum(0.5, parent.sc)
     plot_trace(parent)
     parent.show()
 
+
 def expand_trace(parent):
     parent.level += 1
     parent.level = np.minimum(5, parent.level)
     parent.win.ci.layout.setRowStretchFactor(1, parent.level)
     #parent.p1.zoom_plot()
 
+
 def collapse_trace(parent):
     parent.level -= 1
     parent.level = np.maximum(1, parent.level)
     parent.win.ci.layout.setRowStretchFactor(1, parent.level)
     #parent.p1.zoom_plot()
 
+
 def nc_chosen(parent):
     if parent.loaded:
         plot_trace(parent)
         parent.show()
 
+
 #Agus
 def deconv_on(parent):
     state = parent.checkBoxd.isChecked()
@@ -216,6 +212,7 @@ def deconv_on(parent):
         parent.win.show()
         parent.show()
 
+
 def neuropil_on(parent):
     state = parent.checkBoxn.isChecked()
     if parent.loaded:
@@ -227,6 +224,7 @@ def neuropil_on(parent):
         parent.win.show()
         parent.show()
 
+
 def traces_on(parent):
     state = parent.checkBoxt.isChecked()
     if parent.loaded:
diff --git a/suite2p/gui/utils.py b/suite2p/gui/utils.py
index 865a7b535..894ec4692 100644
--- a/suite2p/gui/utils.py
+++ b/suite2p/gui/utils.py
@@ -1,22 +1,25 @@
 import numpy as np
 from scipy.ndimage.morphology import binary_dilation, binary_fill_holes
 
-def boundary(ypix,xpix):
+
+def boundary(ypix, xpix):
     """ returns pixels of mask that are on the exterior of the mask """
-    ypix = np.expand_dims(ypix.flatten(),axis=1)
-    xpix = np.expand_dims(xpix.flatten(),axis=1)
+    ypix = np.expand_dims(ypix.flatten(), axis=1)
+    xpix = np.expand_dims(xpix.flatten(), axis=1)
     npix = ypix.shape[0]
-    if npix>0:
-        msk = np.zeros((np.ptp(ypix)+6, np.ptp(xpix)+6), 'bool')
-        msk[ypix-ypix.min()+3, xpix-xpix.min()+3] = True
+    if npix > 0:
+        msk = np.zeros((np.ptp(ypix) + 6, np.ptp(xpix) + 6), "bool")
+        msk[ypix - ypix.min() + 3, xpix - xpix.min() + 3] = True
         msk = binary_dilation(msk)
         msk = binary_fill_holes(msk)
-        k = np.ones((3,3),dtype=int) # for 4-connected
-        k = np.zeros((3,3),dtype=int); k[1] = 1; k[:,1] = 1 # for 8-connected
-        out = binary_dilation(msk==0, k) & msk
+        k = np.ones((3, 3), dtype=int)  # for 4-connected
+        k = np.zeros((3, 3), dtype=int)
+        k[1] = 1
+        k[:, 1] = 1  # for 8-connected
+        out = binary_dilation(msk == 0, k) & msk
 
         yext, xext = np.nonzero(out)
-        yext, xext = yext+ypix.min()-3, xext+xpix.min()-3
+        yext, xext = yext + ypix.min() - 3, xext + xpix.min() - 3
     else:
         yext = np.zeros((0,))
         xext = np.zeros((0,))
@@ -25,9 +28,9 @@ def boundary(ypix,xpix):
 
 def circle(med, r):
     """ returns pixels of circle with radius 1.25x radius of cell (r) """
-    theta = np.linspace(0.0,2*np.pi,100)
-    x = r*1.25 * np.cos(theta) + med[0]
-    y = r*1.25 * np.sin(theta) + med[1]
+    theta = np.linspace(0.0, 2 * np.pi, 100)
+    x = r * 1.25 * np.cos(theta) + med[0]
+    y = r * 1.25 * np.sin(theta) + med[1]
     x = x.astype(np.int32)
     y = y.astype(np.int32)
-    return x,y
\ No newline at end of file
+    return x, y
diff --git a/suite2p/gui/views.py b/suite2p/gui/views.py
index f8bebcf84..1f193141a 100644
--- a/suite2p/gui/views.py
+++ b/suite2p/gui/views.py
@@ -28,13 +28,13 @@ def make_buttons(parent):
     for names in parent.view_names:
         btn = ViewButton(b, "&" + names, parent)
         parent.viewbtns.addButton(btn, b)
-        if b>0:
+        if b > 0:
             parent.l0.addWidget(btn, b + 2, 0, 1, 1)
         else:
             parent.l0.addWidget(btn, b + 2, 0, 1, 1)
             label = QLabel("sat: ")
             label.setStyleSheet("color: white;")
-            parent.l0.addWidget(label, b+2,1,1,1)
+            parent.l0.addWidget(label, b + 2, 1, 1, 1)
         btn.setEnabled(False)
         b += 1
     parent.viewbtns.setExclusive(True)
@@ -44,11 +44,12 @@ def make_buttons(parent):
     slider.setLow(0)
     slider.setHigh(255)
     slider.setTickPosition(QSlider.TicksBelow)
-    parent.l0.addWidget(slider, 3,1,len(parent.view_names)-2,1)
+    parent.l0.addWidget(slider, 3, 1, len(parent.view_names) - 2, 1)
 
-    b+=2
+    b += 2
     return b
 
+
 def init_views(parent):
     """ make views using parent.ops
 
@@ -65,81 +66,84 @@ def init_views(parent):
 
     """
     parent.Ly, parent.Lx = parent.ops["Ly"], parent.ops["Lx"]
-    parent.views   = np.zeros((7,parent.Ly, parent.Lx, 3), np.float32)
+    parent.views = np.zeros((7, parent.Ly, parent.Lx, 3), np.float32)
     for k in range(7):
-        if k==2:
-            if 'meanImgE' not in parent.ops:
+        if k == 2:
+            if "meanImgE" not in parent.ops:
                 parent.ops = extraction.enhanced_mean_image(parent.ops)
-            mimg = parent.ops['meanImgE']
-        elif k==1:
-            mimg = parent.ops['meanImg']
-            mimg1 = np.percentile(mimg,1)
-            mimg99 = np.percentile(mimg,99)
-            mimg     = (mimg - mimg1) / (mimg99 - mimg1)
-            mimg = np.maximum(0,np.minimum(1,mimg))
-        elif k==3:
-            if 'Vcorr' in parent.ops:
-                vcorr = parent.ops['Vcorr']
-                mimg1 = np.percentile(vcorr,1)
-                mimg99 = np.percentile(vcorr,99)
+            mimg = parent.ops["meanImgE"]
+        elif k == 1:
+            mimg = parent.ops["meanImg"]
+            mimg1 = np.percentile(mimg, 1)
+            mimg99 = np.percentile(mimg, 99)
+            mimg = (mimg - mimg1) / (mimg99 - mimg1)
+            mimg = np.maximum(0, np.minimum(1, mimg))
+        elif k == 3:
+            if "Vcorr" in parent.ops:
+                vcorr = parent.ops["Vcorr"]
+                mimg1 = np.percentile(vcorr, 1)
+                mimg99 = np.percentile(vcorr, 99)
                 vcorr = (vcorr - mimg1) / (mimg99 - mimg1)
-                mimg = mimg1 * np.ones((parent.Ly, parent.Lx),np.float32)
-                mimg[parent.ops['yrange'][0]:parent.ops['yrange'][1],
-                    parent.ops['xrange'][0]:parent.ops['xrange'][1]] = vcorr
-                mimg = np.maximum(0,np.minimum(1,mimg))
+                mimg = mimg1 * np.ones((parent.Ly, parent.Lx), np.float32)
+                mimg[parent.ops["yrange"][0]:parent.ops["yrange"][1],
+                     parent.ops["xrange"][0]:parent.ops["xrange"][1]] = vcorr
+                mimg = np.maximum(0, np.minimum(1, mimg))
             else:
                 mimg = np.zeros((parent.Ly, parent.Lx), np.float32)
-        elif k==4:
-            if 'max_proj' in parent.ops:
-                mproj = parent.ops['max_proj']
-                mimg1 = np.percentile(mproj,1)
-                mimg99 = np.percentile(mproj,99)
+        elif k == 4:
+            if "max_proj" in parent.ops:
+                mproj = parent.ops["max_proj"]
+                mimg1 = np.percentile(mproj, 1)
+                mimg99 = np.percentile(mproj, 99)
                 mproj = (mproj - mimg1) / (mimg99 - mimg1)
-                mimg = np.zeros((parent.Ly, parent.Lx),np.float32)
+                mimg = np.zeros((parent.Ly, parent.Lx), np.float32)
                 try:
-                    mimg[parent.ops['yrange'][0]:parent.ops['yrange'][1],
-                        parent.ops['xrange'][0]:parent.ops['xrange'][1]] = mproj
+                    mimg[parent.ops["yrange"][0]:parent.ops["yrange"][1],
+                         parent.ops["xrange"][0]:parent.ops["xrange"][1]] = mproj
                 except:
-                    print('maxproj not in combined view')
-                mimg = np.maximum(0,np.minimum(1,mimg))
+                    print("maxproj not in combined view")
+                mimg = np.maximum(0, np.minimum(1, mimg))
             else:
                 mimg = 0.5 * np.ones((parent.Ly, parent.Lx), np.float32)
-        elif k==5:
-            if 'meanImg_chan2_corrected' in parent.ops:
-                mimg = parent.ops['meanImg_chan2_corrected']
-                mimg1 = np.percentile(mimg,1)
-                mimg99 = np.percentile(mimg,99)
-                mimg     = (mimg - mimg1) / (mimg99 - mimg1)
-                mimg = np.maximum(0,np.minimum(1,mimg))
-        elif k==6:
-            if 'meanImg_chan2' in parent.ops:
-                mimg = parent.ops['meanImg_chan2']
-                mimg1 = np.percentile(mimg,1)
-                mimg99 = np.percentile(mimg,99)
-                mimg     = (mimg - mimg1) / (mimg99 - mimg1)
-                mimg = np.maximum(0,np.minimum(1,mimg))
+        elif k == 5:
+            if "meanImg_chan2_corrected" in parent.ops:
+                mimg = parent.ops["meanImg_chan2_corrected"]
+                mimg1 = np.percentile(mimg, 1)
+                mimg99 = np.percentile(mimg, 99)
+                mimg = (mimg - mimg1) / (mimg99 - mimg1)
+                mimg = np.maximum(0, np.minimum(1, mimg))
+        elif k == 6:
+            if "meanImg_chan2" in parent.ops:
+                mimg = parent.ops["meanImg_chan2"]
+                mimg1 = np.percentile(mimg, 1)
+                mimg99 = np.percentile(mimg, 99)
+                mimg = (mimg - mimg1) / (mimg99 - mimg1)
+                mimg = np.maximum(0, np.minimum(1, mimg))
         else:
-            mimg = np.zeros((parent.Ly, parent.Lx),np.float32)
+            mimg = np.zeros((parent.Ly, parent.Lx), np.float32)
 
         mimg *= 255
         mimg = mimg.astype(np.uint8)
-        parent.views[k] = np.tile(mimg[:,:,np.newaxis], (1,1,3))
+        parent.views[k] = np.tile(mimg[:, :, np.newaxis], (1, 1, 3))
+
 
 def plot_views(parent):
-    """ set parent.view1 and parent.view2 image based on parent.ops_plot['view']"""
-    k    = parent.ops_plot['view']
-    parent.view1.setImage(parent.views[k], levels=parent.ops_plot['saturation'])
-    parent.view2.setImage(parent.views[k], levels=parent.ops_plot['saturation'])
+    """ set parent.view1 and parent.view2 image based on parent.ops_plot["view"]"""
+    k = parent.ops_plot["view"]
+    parent.view1.setImage(parent.views[k], levels=parent.ops_plot["saturation"])
+    parent.view2.setImage(parent.views[k], levels=parent.ops_plot["saturation"])
     parent.view1.show()
     parent.view2.show()
 
+
 class ViewButton(QPushButton):
     """ custom QPushButton class for quadrant plotting
         requires buttons to put into a QButtonGroup (parent.viewbtns)
          allows only 1 button to pressed at a time
     """
+
     def __init__(self, bid, Text, parent=None):
-        super(ViewButton,self).__init__(parent)
+        super(ViewButton, self).__init__(parent)
         self.setText(Text)
         self.setCheckable(True)
         self.setStyleSheet(parent.styleInactive)
@@ -147,12 +151,13 @@ def __init__(self, bid, Text, parent=None):
         self.resize(self.minimumSizeHint())
         self.clicked.connect(lambda: self.press(parent, bid))
         self.show()
+
     def press(self, parent, bid):
         for b in range(len(parent.views)):
             if parent.viewbtns.button(b).isEnabled():
                 parent.viewbtns.button(b).setStyleSheet(parent.styleUnpressed)
         self.setStyleSheet(parent.stylePressed)
-        parent.ops_plot['view'] = bid
+        parent.ops_plot["view"] = bid
         parent.update_plot()
 
 
@@ -169,6 +174,7 @@ class RangeSlider(QSlider):
         Found this slider here: https://www.mail-archive.com/pyqt@riverbankcomputing.com/msg22889.html
         and modified it
     """
+
     def __init__(self, parent=None, *args):
         super(RangeSlider, self).__init__(*args)
 
@@ -190,8 +196,7 @@ def __init__(self, parent=None, *args):
                 height: 8px;\
                 width: 6px;\
                 margin: -8px 2; \
-                }")
-
+                }"                                                                        )
 
         #self.opt = QStyleOptionSlider()
         #self.opt.orientation=QtCore.Qt.Vertical
@@ -203,7 +208,7 @@ def __init__(self, parent=None, *args):
     def level_change(self):
         if self.parent is not None:
             if self.parent.loaded:
-                self.parent.ops_plot['saturation'] = [self._low, self._high]
+                self.parent.ops_plot["saturation"] = [self._low, self._high]
                 self.parent.update_plot()
 
     def low(self):
@@ -229,10 +234,10 @@ def paintEvent(self, event):
             opt = QStyleOptionSlider()
             self.initStyleOption(opt)
 
-            # Only draw the groove for the first slider so it doesn't get drawn
+            # Only draw the groove for the first slider so it doesn"t get drawn
             # on top of the existing ones every time
             if i == 0:
-                opt.subControls = QStyle.SC_SliderHandle#QStyle.SC_SliderGroove | QStyle.SC_SliderHandle
+                opt.subControls = QStyle.SC_SliderHandle  #QStyle.SC_SliderGroove | QStyle.SC_SliderHandle
             else:
                 opt.subControls = QStyle.SC_SliderHandle
 
@@ -249,14 +254,13 @@ def paintEvent(self, event):
             opt.sliderValue = value
             style.drawComplexControl(QStyle.CC_Slider, opt, painter, self)
 
-
     def mousePressEvent(self, event):
         event.accept()
 
         style = QApplication.style()
         button = event.button()
         # In a normal slider control, when the user clicks on a point in the
-        # slider's total range, but not on the slider part of the control the
+        # slider"s total range, but not on the slider part of the control the
         # control would jump the slider value to where the user clicked.
         # For this control, clicks which are not direct hits will slide both
         # slider parts
@@ -268,7 +272,8 @@ def mousePressEvent(self, event):
 
             for i, value in enumerate([self._low, self._high]):
                 opt.sliderPosition = value
-                hit = style.hitTestComplexControl(style.CC_Slider, opt, event.pos(), self)
+                hit = style.hitTestComplexControl(style.CC_Slider, opt, event.pos(),
+                                                  self)
                 if hit == style.SC_SliderHandle:
                     self.active_slider = i
                     self.pressed_control = hit
@@ -281,7 +286,8 @@ def mousePressEvent(self, event):
 
             if self.active_slider < 0:
                 self.pressed_control = QStyle.SC_SliderHandle
-                self.click_offset = self.__pixelPosToRangeValue(self.__pick(event.pos()))
+                self.click_offset = self.__pixelPosToRangeValue(self.__pick(
+                    event.pos()))
                 self.triggerAction(self.SliderMove)
                 self.setRepeatAction(self.SliderNoAction)
         else:
@@ -330,7 +336,6 @@ def __pick(self, pt):
         else:
             return pt.y()
 
-
     def __pixelPosToRangeValue(self, pos):
         opt = QStyleOptionSlider()
         self.initStyleOption(opt)
@@ -349,5 +354,5 @@ def __pixelPosToRangeValue(self, pos):
             slider_max = gr.bottom() - slider_length + 1
 
         return style.sliderValueFromPosition(self.minimum(), self.maximum(),
-                                             pos-slider_min, slider_max-slider_min,
+                                             pos - slider_min, slider_max - slider_min,
                                              opt.upsideDown)
diff --git a/suite2p/gui/visualize.py b/suite2p/gui/visualize.py
index 35992f8b0..e4cf27d80 100644
--- a/suite2p/gui/visualize.py
+++ b/suite2p/gui/visualize.py
@@ -4,7 +4,7 @@
 import numpy as np
 import pyqtgraph as pg
 from PyQt5 import QtGui, QtCore
-from PyQt5.QtWidgets import QStyle 
+from PyQt5.QtWidgets import QStyle
 from PyQt5.QtWidgets import QWidget, QSlider, QMainWindow, QGridLayout, QStyleOptionSlider, QApplication, QLabel, QLineEdit, QPushButton, QComboBox, QCheckBox
 from matplotlib import cm
 from rastermap.mapping import Rastermap
@@ -16,6 +16,7 @@
 
 # custom vertical label
 class VerticalLabel(QWidget):
+
     def __init__(self, text=None):
         super(self.__class__, self).__init__()
         self.text = text
@@ -29,6 +30,7 @@ def paintEvent(self, event):
             painter.drawText(0, 0, self.text)
         painter.end()
 
+
 class RangeSlider(QSlider):
     """ A slider for ranges.
 
@@ -42,6 +44,7 @@ class RangeSlider(QSlider):
         Found this slider here: https://www.mail-archive.com/pyqt@riverbankcomputing.com/msg22889.html
         and modified it
     """
+
     def __init__(self, parent=None, *args):
         super(RangeSlider, self).__init__(*args)
 
@@ -63,7 +66,7 @@ def __init__(self, parent=None, *args):
                 height: 8px;\
                 width: 6px;\
                 margin: -8px 2; \
-                }")
+                }"                                                                        )
         # 0 for the low, 1 for the high, -1 for both
         self.active_slider = 0
         self.parent = parent
@@ -92,10 +95,10 @@ def paintEvent(self, event):
         for i, value in enumerate([self._low, self._high]):
             opt = QStyleOptionSlider()
             self.initStyleOption(opt)
-            # Only draw the groove for the first slider so it doesn't get drawn
+            # Only draw the groove for the first slider so it doesn"t get drawn
             # on top of the existing ones every time
             if i == 0:
-                opt.subControls = QStyle.SC_SliderHandle#QStyle.SC_SliderGroove | QStyle.SC_SliderHandle
+                opt.subControls = QStyle.SC_SliderHandle  #QStyle.SC_SliderGroove | QStyle.SC_SliderHandle
             else:
                 opt.subControls = QStyle.SC_SliderHandle
             if self.tickPosition() != self.NoTicks:
@@ -119,7 +122,8 @@ def mousePressEvent(self, event):
             self.active_slider = -1
             for i, value in enumerate([self._low, self._high]):
                 opt.sliderPosition = value
-                hit = style.hitTestComplexControl(style.CC_Slider, opt, event.pos(), self)
+                hit = style.hitTestComplexControl(style.CC_Slider, opt, event.pos(),
+                                                  self)
                 if hit == style.SC_SliderHandle:
                     self.active_slider = i
                     self.pressed_control = hit
@@ -129,11 +133,13 @@ def mousePressEvent(self, event):
                     break
             if self.active_slider < 0:
                 self.pressed_control = QStyle.SC_SliderHandle
-                self.click_offset = self.__pixelPosToRangeValue(self.__pick(event.pos()))
+                self.click_offset = self.__pixelPosToRangeValue(self.__pick(
+                    event.pos()))
                 self.triggerAction(self.SliderMove)
                 self.setRepeatAction(self.SliderNoAction)
         else:
             event.ignore()
+
     def mouseMoveEvent(self, event):
         if self.pressed_control != QStyle.SC_SliderHandle:
             event.ignore()
@@ -164,13 +170,16 @@ def mouseMoveEvent(self, event):
             self._high = new_pos
         self.click_offset = new_pos
         self.update()
+
     def mouseReleaseEvent(self, event):
         self.level_change()
+
     def __pick(self, pt):
         if self.orientation() == QtCore.Qt.Horizontal:
             return pt.x()
         else:
             return pt.y()
+
     def __pixelPosToRangeValue(self, pos):
         opt = QStyleOptionSlider()
         self.initStyleOption(opt)
@@ -189,10 +198,12 @@ def __pixelPosToRangeValue(self, pos):
             slider_max = gr.bottom() - slider_length + 1
 
         return style.sliderValueFromPosition(self.minimum(), self.maximum(),
-                                             pos-slider_min, slider_max-slider_min,
+                                             pos - slider_min, slider_max - slider_min,
                                              opt.upsideDown)
 
+
 class SatSlider(RangeSlider):
+
     def __init__(self, parent=None):
         super(SatSlider, self).__init__(parent)
         self.parent = parent
@@ -202,13 +213,15 @@ def __init__(self, parent=None):
         self.setHigh(70)
 
     def level_change(self):
-        self.parent.sat[0] = float(self._low)/100
-        self.parent.sat[1] = float(self._high)/100
-        self.parent.img.setLevels([self.parent.sat[0],self.parent.sat[1]])
-        self.parent.imgROI.setLevels([self.parent.sat[0],self.parent.sat[1]])
+        self.parent.sat[0] = float(self._low) / 100
+        self.parent.sat[1] = float(self._high) / 100
+        self.parent.img.setLevels([self.parent.sat[0], self.parent.sat[1]])
+        self.parent.imgROI.setLevels([self.parent.sat[0], self.parent.sat[1]])
         self.parent.win.show()
 
+
 class NeuronSlider(RangeSlider):
+
     def __init__(self, parent=None):
         super(SatSlider, self).__init__(parent)
         self.parent = parent
@@ -218,134 +231,137 @@ def __init__(self, parent=None):
         self.setHigh(70)
 
     def level_change(self):
-        self.parent.sat[0] = float(self._low)/100
-        self.parent.sat[1] = float(self._high)/100
-        self.parent.img.setLevels([self.parent.sat[0],self.parent.sat[1]])
-        self.parent.imgROI.setLevels([self.parent.sat[0],self.parent.sat[1]])
+        self.parent.sat[0] = float(self._low) / 100
+        self.parent.sat[1] = float(self._high) / 100
+        self.parent.img.setLevels([self.parent.sat[0], self.parent.sat[1]])
+        self.parent.imgROI.setLevels([self.parent.sat[0], self.parent.sat[1]])
         self.parent.win.show()
 
+
 class Slider(QSlider):
+
     def __init__(self, bid, parent=None):
         super(self.__class__, self).__init__()
         self.bid = bid
         self.setMinimum(0)
         self.setMaximum(100)
-        self.setValue(parent.sat[bid]*100)
+        self.setValue(parent.sat[bid] * 100)
         self.setTickPosition(QSlider.TicksLeft)
         self.setTickInterval(10)
-        self.valueChanged.connect(lambda: self.level_change(parent,bid))
+        self.valueChanged.connect(lambda: self.level_change(parent, bid))
         self.setTracking(False)
 
     def level_change(self, parent, bid):
-        parent.sat[bid] = float(self.value())/100
-        parent.img.setLevels([parent.sat[0],parent.sat[1]])
-        parent.imgROI.setLevels([parent.sat[0],parent.sat[1]])
+        parent.sat[bid] = float(self.value()) / 100
+        parent.img.setLevels([parent.sat[0], parent.sat[1]])
+        parent.imgROI.setLevels([parent.sat[0], parent.sat[1]])
         parent.win.show()
 
 
-
 ### custom QDialog which allows user to fill in ops and run suite2p!
 class VisWindow(QMainWindow):
+
     def __init__(self, parent=None):
         super(VisWindow, self).__init__(parent)
         self.parent = parent
-        pg.setConfigOptions(imageAxisOrder='row-major')
-        self.setGeometry(70,70,1100,900)
-        self.setWindowTitle('Visualize data')
+        pg.setConfigOptions(imageAxisOrder="row-major")
+        self.setGeometry(70, 70, 1100, 900)
+        self.setWindowTitle("Visualize data")
         self.cwidget = QWidget(self)
         self.setCentralWidget(self.cwidget)
         self.l0 = QGridLayout()
         #layout = QtGui.QFormLayout()
         self.cwidget.setLayout(self.l0)
-        #self.p0 = pg.ViewBox(lockAspect=False,name='plot1',border=[100,100,100],invertY=True)
+        #self.p0 = pg.ViewBox(lockAspect=False,name="plot1",border=[100,100,100],invertY=True)
         self.win = pg.GraphicsLayoutWidget()
         # --- cells image
         self.win = pg.GraphicsLayoutWidget()
-        self.win.move(600,0)
-        self.win.resize(1000,500)
-        self.l0.addWidget(self.win,0,0,14,14)
+        self.win.move(600, 0)
+        self.win.resize(1000, 500)
+        self.l0.addWidget(self.win, 0, 0, 14, 14)
         layout = self.win.ci.layout
         # A plot area (ViewBox + axes) for displaying the image
-        self.p0 = self.win.addViewBox(row=0,col=0)
-        self.p0.setMouseEnabled(x=False,y=False)
+        self.p0 = self.win.addViewBox(row=0, col=0)
+        self.p0.setMouseEnabled(x=False, y=False)
         self.p0.setMenuEnabled(False)
-        self.p1 = self.win.addPlot(title="FULL VIEW",row=0,col=1)
-        self.p1.setMouseEnabled(x=False,y=False)
+        self.p1 = self.win.addPlot(title="FULL VIEW", row=0, col=1)
+        self.p1.setMouseEnabled(x=False, y=False)
         self.img = pg.ImageItem(autoDownsample=True)
         self.p1.addItem(self.img)
         # cells to plot
-        if len(self.parent.imerge)==1:
+        if len(self.parent.imerge) == 1:
             icell = self.parent.iscell[self.parent.imerge[0]]
-            self.cells = np.array((self.parent.iscell==icell).nonzero()).flatten()
+            self.cells = np.array((self.parent.iscell == icell).nonzero()).flatten()
         else:
             self.cells = np.array(self.parent.imerge).flatten()
         # compute spikes
         i = self.parent.activityMode
-        if i==0:
-            sp = self.parent.Fcell[self.cells,:]
-        elif i==1:
-            sp = self.parent.Fneu[self.cells,:]
-        elif i==2:
-            sp = self.parent.Fcell[self.cells,:] - 0.7*self.parent.Fneu[self.cells,:]
+        if i == 0:
+            sp = self.parent.Fcell[self.cells, :]
+        elif i == 1:
+            sp = self.parent.Fneu[self.cells, :]
+        elif i == 2:
+            sp = self.parent.Fcell[
+                self.cells, :] - 0.7 * self.parent.Fneu[self.cells, :]
         else:
-            sp = self.parent.Spks[self.cells,:]
+            sp = self.parent.Spks[self.cells, :]
         sp = np.squeeze(sp)
         sp = zscore(sp, axis=1)
-        self.sp = np.maximum(-4,np.minimum(8,sp)) + 4
+        self.sp = np.maximum(-4, np.minimum(8, sp)) + 4
         self.sp /= 12
-        self.tsort = np.arange(0,sp.shape[1]).astype(np.int32)
+        self.tsort = np.arange(0, sp.shape[1]).astype(np.int32)
         # 100 ms bins
-        self.bin = int(np.maximum(1, int(self.parent.ops['fs']/10)))
+        self.bin = int(np.maximum(1, int(self.parent.ops["fs"] / 10)))
         # draw axes
-        self.p1.setXRange(0,sp.shape[1])
-        self.p1.setYRange(0,sp.shape[0])
-        self.p1.setLimits(xMin=-10,xMax=sp.shape[1]+10,yMin=-10,yMax=sp.shape[0]+10)
-        self.p1.setLabel('left', 'neurons')
-        self.p1.setLabel('bottom', 'time')
+        self.p1.setXRange(0, sp.shape[1])
+        self.p1.setYRange(0, sp.shape[0])
+        self.p1.setLimits(xMin=-10, xMax=sp.shape[1] + 10, yMin=-10,
+                          yMax=sp.shape[0] + 10)
+        self.p1.setLabel("left", "neurons")
+        self.p1.setLabel("bottom", "time")
         # zoom in on a selected image region
         nt = sp.shape[1]
         nn = sp.shape[0]
-        self.selected = np.arange(0,nn,1,int)
-        self.p2 = self.win.addPlot(title='ZOOM IN',row=1,col=0,colspan=2)
+        self.selected = np.arange(0, nn, 1, int)
+        self.p2 = self.win.addPlot(title="ZOOM IN", row=1, col=0, colspan=2)
         self.imgROI = pg.ImageItem(autoDownsample=True)
         self.p2.addItem(self.imgROI)
-        self.p2.setMouseEnabled(x=False,y=False)
-        #self.p2.setLabel('left', 'neurons')
-        self.p2.hideAxis('bottom')
+        self.p2.setMouseEnabled(x=False, y=False)
+        #self.p2.setLabel("left", "neurons")
+        self.p2.hideAxis("bottom")
         self.bloaded = self.parent.bloaded
-        self.p3 = self.win.addPlot(title='',row=2,col=0,colspan=2)
-        self.p3.setMouseEnabled(x=False,y=False)
-        #self.p3.getAxis('left').setTicks([[(0,'')]])
-        self.p3.setLabel('bottom', 'time')
+        self.p3 = self.win.addPlot(title="", row=2, col=0, colspan=2)
+        self.p3.setMouseEnabled(x=False, y=False)
+        #self.p3.getAxis("left").setTicks([[(0,"")]])
+        self.p3.setLabel("bottom", "time")
         # set colormap to viridis
         colormap = cm.get_cmap("gray_r")
         colormap._init()
-        lut = (colormap._lut * 255).view(np.ndarray)  # Convert matplotlib colormap from 0-1 to 0 -255 for Qt
-        lut = lut[0:-3,:]
+        lut = (colormap._lut * 255).view(
+            np.ndarray)  # Convert matplotlib colormap from 0-1 to 0 -255 for Qt
+        lut = lut[0:-3, :]
         # apply the colormap
         self.img.setLookupTable(lut)
         self.imgROI.setLookupTable(lut)
-        layout.setColumnStretchFactor(1,3)
-        layout.setRowStretchFactor(1,3)
+        layout.setColumnStretchFactor(1, 3)
+        layout.setRowStretchFactor(1, 3)
         # add slider for levels
-        self.sat = [0.3,0.7]
+        self.sat = [0.3, 0.7]
         slider = SatSlider(self)
         slider.setTickPosition(QSlider.TicksBelow)
-        self.l0.addWidget(slider, 0,2,5,1)
-        qlabel = VerticalLabel(text='saturation')
-        qlabel.setStyleSheet('color: white;')
+        self.l0.addWidget(slider, 0, 2, 5, 1)
+        qlabel = VerticalLabel(text="saturation")
+        qlabel.setStyleSheet("color: white;")
         self.img.setLevels([self.sat[0], self.sat[1]])
         self.imgROI.setLevels([self.sat[0], self.sat[1]])
-        self.l0.addWidget(qlabel,2,3,3,2)
-        self.isort = np.arange(0,self.cells.size).astype(np.int32)
+        self.l0.addWidget(qlabel, 2, 3, 3, 2)
+        self.isort = np.arange(0, self.cells.size).astype(np.int32)
         # ROI on main plot
-        redpen = pg.mkPen(pg.mkColor(255, 0, 0),
-                                width=3,
-                                style=QtCore.Qt.SolidLine)
-        self.ROI = pg.RectROI([nt*.25, -1], [nt*.25, nn+1],
-                      maxBounds=QtCore.QRectF(-1.,-1.,nt+1,nn+1),
-                      pen=redpen)
-        self.xrange = np.arange(nt*.25, nt*.5,1,int)
+        redpen = pg.mkPen(pg.mkColor(255, 0, 0), width=3, style=QtCore.Qt.SolidLine)
+        self.ROI = pg.RectROI([nt * .25, -1], [nt * .25, nn + 1],
+                              maxBounds=QtCore.QRectF(-1., -1., nt + 1,
+                                                      nn + 1), pen=redpen)
+        self.xrange = np.arange(nt * .25, nt * .5, 1, int)
         self.ROI.handleSize = 10
         self.ROI.handlePen = redpen
         # Add right Handle
@@ -356,10 +372,10 @@ def __init__(self, parent=None):
         self.p1.addItem(self.ROI)
         self.ROI.setZValue(10)  # make sure ROI is drawn above image
 
-        self.LINE = pg.RectROI([-1, nn*.4], [nt*.25, nn*.2],
-                      maxBounds=QtCore.QRectF(-1,-1.,nt*.25,nn+1),
-                      pen=redpen)
-        self.selected = np.arange(nn*.4, nn*.6, 1, int)
+        self.LINE = pg.RectROI([-1, nn * .4], [nt * .25, nn * .2],
+                               maxBounds=QtCore.QRectF(-1, -1., nt * .25,
+                                                       nn + 1), pen=redpen)
+        self.selected = np.arange(nn * .4, nn * .6, 1, int)
         self.LINE.handleSize = 10
         self.LINE.handlePen = redpen
         # Add top handle
@@ -370,13 +386,10 @@ def __init__(self, parent=None):
         self.p2.addItem(self.LINE)
         self.LINE.setZValue(10)  # make sure ROI is drawn above image
 
-
-        greenpen = pg.mkPen(pg.mkColor(0, 255, 0),
-                                width=3,
-                                style=QtCore.Qt.SolidLine)
-        self.THRES = pg.RectROI([-0.5, 0], [nt*.25, 1],
-                      maxBounds=QtCore.QRectF(-1.,-10.,nt*.25,10),
-                      pen=greenpen)
+        greenpen = pg.mkPen(pg.mkColor(0, 255, 0), width=3, style=QtCore.Qt.SolidLine)
+        self.THRES = pg.RectROI([-0.5, 0], [nt * .25, 1],
+                                maxBounds=QtCore.QRectF(-1., -10., nt * .25,
+                                                        10), pen=greenpen)
         self.THRES.handleSize = 10
         self.THRES.handlePen = greenpen
         # Add top handle
@@ -391,22 +404,22 @@ def __init__(self, parent=None):
 
         self.neural_sorting(2)
         # buttons for computations
-        self.mapOn = QPushButton('compute rastermap + PCs')
+        self.mapOn = QPushButton("compute rastermap + PCs")
         self.mapOn.clicked.connect(self.compute_map)
-        self.l0.addWidget(self.mapOn,0,0,1,2)
+        self.l0.addWidget(self.mapOn, 0, 0, 1, 2)
         self.comboBox = QComboBox(self)
-        self.l0.addWidget(self.comboBox,1,0,1,2)
-        self.l0.addWidget(QLabel('PC 1:'),2,0,1,2)
-        #self.l0.addWidget(QLabel(''),4,0,1,1)
-        self.selectBtn = QPushButton('show selected cells in GUI')
+        self.l0.addWidget(self.comboBox, 1, 0, 1, 2)
+        self.l0.addWidget(QLabel("PC 1:"), 2, 0, 1, 2)
+        #self.l0.addWidget(QLabel(""),4,0,1,1)
+        self.selectBtn = QPushButton("show selected cells in GUI")
         self.selectBtn.clicked.connect(self.select_cells)
         self.selectBtn.setEnabled(True)
-        self.l0.addWidget(self.selectBtn,3,0,1,2)
-        self.sortTime = QCheckBox('&Time sort')
+        self.l0.addWidget(self.selectBtn, 3, 0, 1, 2)
+        self.sortTime = QCheckBox("&Time sort")
         self.sortTime.setStyleSheet("color: white;")
         self.sortTime.stateChanged.connect(self.sort_time)
-        self.l0.addWidget(self.sortTime,4,0,1,2)
-        self.l0.addWidget(QLabel(''),5,0,1,1)
+        self.l0.addWidget(self.sortTime, 4, 0, 1, 2)
+        self.l0.addWidget(QLabel(""), 5, 0, 1, 1)
         self.l0.setRowStretch(6, 1)
         self.raster = False
 
@@ -421,173 +434,173 @@ def __init__(self, parent=None):
         self.win.scene().sigMouseClicked.connect(self.plot_clicked)
         self.show()
 
-    def plot_clicked(self,event):
+    def plot_clicked(self, event):
         items = self.win.scene().items(event.scenePos())
         for x in items:
-            if x==self.p1:
-                if event.button()==1:
+            if x == self.p1:
+                if event.button() == 1:
                     if event.double():
-                        self.ROI.setPos([-1,-1])
-                        self.ROI.setSize([self.sp.shape[1]+1, self.sp.shape[0]+1])
+                        self.ROI.setPos([-1, -1])
+                        self.ROI.setSize([self.sp.shape[1] + 1, self.sp.shape[0] + 1])
 
     def keyPressEvent(self, event):
         bid = -1
         move = False
-        nn,nt = self.sp.shape
-        if event.modifiers() !=  QtCore.Qt.ShiftModifier:
+        nn, nt = self.sp.shape
+        if event.modifiers() != QtCore.Qt.ShiftModifier:
             if event.key() == QtCore.Qt.Key_Down:
                 bid = 0
             elif event.key() == QtCore.Qt.Key_Up:
-                bid=1
+                bid = 1
             elif event.key() == QtCore.Qt.Key_Left:
-                bid=2
+                bid = 2
             elif event.key() == QtCore.Qt.Key_Right:
-                bid=3
-            if bid==2 or bid==3:
-                xrange,yrange = self.roi_range(self.ROI)
+                bid = 3
+            if bid == 2 or bid == 3:
+                xrange, yrange = self.roi_range(self.ROI)
                 if xrange.size < nt:
                     # can move
-                    if bid==2:
+                    if bid == 2:
                         move = True
-                        xrange = xrange - np.minimum(xrange.min()+1,nt*0.05)
+                        xrange = xrange - np.minimum(xrange.min() + 1, nt * 0.05)
                     else:
                         move = True
-                        xrange = xrange + np.minimum(nt-xrange.max()-1,nt*0.05)
+                        xrange = xrange + np.minimum(nt - xrange.max() - 1, nt * 0.05)
                     if move:
-                        self.ROI.setPos([xrange.min()-1, -1])
-                        self.ROI.setSize([xrange.size+1, nn+1])
-            if bid==0 or bid==1:
-                xrange,yrange = self.roi_range(self.LINE)
+                        self.ROI.setPos([xrange.min() - 1, -1])
+                        self.ROI.setSize([xrange.size + 1, nn + 1])
+            if bid == 0 or bid == 1:
+                xrange, yrange = self.roi_range(self.LINE)
                 if yrange.size < nn:
                     # can move
-                    if bid==0:
+                    if bid == 0:
                         move = True
-                        yrange = yrange - np.minimum(yrange.min(),nn*0.05)
+                        yrange = yrange - np.minimum(yrange.min(), nn * 0.05)
                     else:
                         move = True
-                        yrange = yrange + np.minimum(nn-yrange.max()-1,nn*0.05)
+                        yrange = yrange + np.minimum(nn - yrange.max() - 1, nn * 0.05)
                     if move:
                         self.LINE.setPos([-1, yrange.min()])
-                        self.LINE.setSize([self.xrange.size+1,  yrange.size])
+                        self.LINE.setSize([self.xrange.size + 1, yrange.size])
         else:
             if event.key() == QtCore.Qt.Key_Down:
                 bid = 0
             elif event.key() == QtCore.Qt.Key_Up:
-                bid=1
+                bid = 1
             elif event.key() == QtCore.Qt.Key_Left:
-                bid=2
+                bid = 2
             elif event.key() == QtCore.Qt.Key_Right:
-                bid=3
-            if bid==2 or bid==3:
-                xrange,_ = self.roi_range(self.ROI)
-                dx = nt*0.05 / (nt/xrange.size)
-                if bid==2:
+                bid = 3
+            if bid == 2 or bid == 3:
+                xrange, _ = self.roi_range(self.ROI)
+                dx = nt * 0.05 / (nt / xrange.size)
+                if bid == 2:
                     if xrange.size > dx:
                         # can move
                         move = True
                         xmax = xrange.size - dx
-                        xrange = xrange.min() + np.arange(0,xmax).astype(np.int32)
+                        xrange = xrange.min() + np.arange(0, xmax).astype(np.int32)
                 else:
-                    if xrange.size < nt-dx + 1:
+                    if xrange.size < nt - dx + 1:
                         move = True
                         xmax = xrange.size + dx
-                        xrange = xrange.min() + np.arange(0,xmax).astype(np.int32)
+                        xrange = xrange.min() + np.arange(0, xmax).astype(np.int32)
                 if move:
-                    self.ROI.setPos([xrange.min()-1, -1])
-                    self.ROI.setSize([xrange.size+1, nn+1])
+                    self.ROI.setPos([xrange.min() - 1, -1])
+                    self.ROI.setSize([xrange.size + 1, nn + 1])
 
-            elif bid>=0:
-                _,yrange = self.roi_range(self.LINE)
-                dy = nn*0.05 / (nn/yrange.size)
-                if bid==0:
+            elif bid >= 0:
+                _, yrange = self.roi_range(self.LINE)
+                dy = nn * 0.05 / (nn / yrange.size)
+                if bid == 0:
                     if yrange.size > dy:
                         # can move
                         move = True
                         ymax = yrange.size - dy
-                        yrange = yrange.min() + np.arange(0,ymax).astype(np.int32)
+                        yrange = yrange.min() + np.arange(0, ymax).astype(np.int32)
                 else:
-                    if yrange.size < nn-dy + 1:
+                    if yrange.size < nn - dy + 1:
                         move = True
                         ymax = yrange.size + dy
-                        yrange = yrange.min() + np.arange(0,ymax).astype(np.int32)
+                        yrange = yrange.min() + np.arange(0, ymax).astype(np.int32)
                 if move:
                     self.LINE.setPos([-1, yrange.min()])
-                    self.LINE.setSize([self.xrange.size+1,  yrange.size])
-
+                    self.LINE.setSize([self.xrange.size + 1, yrange.size])
 
     def roi_range(self, roi):
         pos = roi.pos()
         posy = pos.y()
         posx = pos.x()
-        sizex,sizey = roi.size()
-        xrange = (np.arange(0,int(sizex)) + int(posx)).astype(np.int32)
-        yrange = (np.arange(0,int(sizey)) + int(posy)).astype(np.int32)
-        xrange = xrange[xrange>=0]
-        xrange = xrange[xrange<self.sp.shape[1]]
-        yrange = yrange[yrange>=0]
-        yrange = yrange[yrange<self.sp.shape[0]]
-        return xrange,yrange
+        sizex, sizey = roi.size()
+        xrange = (np.arange(0, int(sizex)) + int(posx)).astype(np.int32)
+        yrange = (np.arange(0, int(sizey)) + int(posy)).astype(np.int32)
+        xrange = xrange[xrange >= 0]
+        xrange = xrange[xrange < self.sp.shape[1]]
+        yrange = yrange[yrange >= 0]
+        yrange = yrange[yrange < self.sp.shape[0]]
+        return xrange, yrange
 
     def plot_traces(self):
-        avg = self.spF[np.ix_(self.selected,self.xrange)].mean(axis=0)
+        avg = self.spF[np.ix_(self.selected, self.xrange)].mean(axis=0)
         avg -= avg.min()
         avg /= avg.max()
         self.p3.clear()
-        self.p3.plot(self.xrange,avg,pen=(255,0,0))
+        self.p3.plot(self.xrange, avg, pen=(255, 0, 0))
         if self.bloaded:
-            self.p3.plot(self.parent.beh_time,self.parent.beh,pen='w')
-        self.p3.setXRange(self.xrange[0],self.xrange[-1])
+            self.p3.plot(self.parent.beh_time, self.parent.beh, pen="w")
+        self.p3.setXRange(self.xrange[0], self.xrange[-1])
         self.p3.addItem(self.THRES)
         self.THRES.setZValue(10)  # make sure ROI is drawn above image
 
     def LINE_position(self):
-        _,yrange = self.roi_range(self.LINE)
-        self.selected = yrange.astype('int')
+        _, yrange = self.roi_range(self.LINE)
+        self.selected = yrange.astype("int")
         self.plot_traces()
 
     def THRES_position(self):
         pos = self.THRES.pos()
         posy = pos.y()
-        sizex,sizey = self.THRES.size()
+        sizex, sizey = self.THRES.size()
         self.tpos = posy
         self.tsize = sizey
 
     def ROI_position(self):
-        xrange,_ = self.roi_range(self.ROI)
+        xrange, _ = self.roi_range(self.ROI)
         self.xrange = xrange
         self.imgROI.setImage(self.spF[:, self.xrange])
-        self.p2.setXRange(0,self.xrange.size)
+        self.p2.setXRange(0, self.xrange.size)
 
         self.plot_traces()
 
         # reset ROIs
-        self.LINE.maxBounds = QtCore.QRectF(-1,-1.,
-                                xrange.size+1,self.sp.shape[0]+1)
-        self.LINE.setSize([xrange.size+1, self.selected.size])
+        self.LINE.maxBounds = QtCore.QRectF(-1, -1., xrange.size + 1,
+                                            self.sp.shape[0] + 1)
+        self.LINE.setSize([xrange.size + 1, self.selected.size])
         self.LINE.setZValue(10)
 
-        self.THRES.maxBounds = QtCore.QRectF(self.xrange[0]-1,-5.,
-                                self.xrange[1]+1,10)
-        self.THRES.setPos([self.xrange[0]-1, self.tpos])
-        self.THRES.setSize([xrange.size+1, self.tsize])
+        self.THRES.maxBounds = QtCore.QRectF(self.xrange[0] - 1, -5.,
+                                             self.xrange[1] + 1, 10)
+        self.THRES.setPos([self.xrange[0] - 1, self.tpos])
+        self.THRES.setSize([xrange.size + 1, self.tsize])
         self.THRES.setZValue(10)
 
-        axy = self.p2.getAxis('left')
-        axx = self.p2.getAxis('bottom')
+        axy = self.p2.getAxis("left")
+        axx = self.p2.getAxis("bottom")
         #axy.setTicks([[(0.0,str(yrange[0])),(float(yrange.size),str(yrange[-1]))]])
         self.imgROI.setLevels([self.sat[0], self.sat[1]])
 
     def PC_on(self, plot):
         # edit buttons
         self.PCedit = QLineEdit(self)
-        self.PCedit.setValidator(QtGui.QIntValidator(1,np.minimum(self.sp.shape[0],self.sp.shape[1])))
-        self.PCedit.setText('1')
+        self.PCedit.setValidator(
+            QtGui.QIntValidator(1, np.minimum(self.sp.shape[0], self.sp.shape[1])))
+        self.PCedit.setText("1")
         self.PCedit.setFixedWidth(60)
         self.PCedit.setAlignment(QtCore.Qt.AlignRight)
-        qlabel = QLabel('PC: ')
-        qlabel.setStyleSheet('color: white;')
-        self.l0.addWidget(qlabel,3,0,1,1)
-        self.l0.addWidget(self.PCedit,3,1,1,1)
+        qlabel = QLabel("PC: ")
+        qlabel.setStyleSheet("color: white;")
+        self.l0.addWidget(qlabel, 3, 0, 1, 1)
+        self.l0.addWidget(self.PCedit, 3, 1, 1, 1)
         self.comboBox.addItem("PC")
         self.PCedit.returnPressed.connect(self.PCreturn)
         self.compute_svd(self.bin)
@@ -603,20 +616,21 @@ def PCreturn(self):
     def activate(self):
         # activate buttons
         self.PCedit = QLineEdit(self)
-        self.PCedit.setValidator(QtGui.QIntValidator(1,np.minimum(self.sp.shape[0],self.sp.shape[1])))
-        self.PCedit.setText('1')
+        self.PCedit.setValidator(
+            QtGui.QIntValidator(1, np.minimum(self.sp.shape[0], self.sp.shape[1])))
+        self.PCedit.setText("1")
         self.PCedit.setFixedWidth(60)
         self.PCedit.setAlignment(QtCore.Qt.AlignRight)
-        qlabel = QLabel('PC: ')
-        qlabel.setStyleSheet('color: white;')
-        self.l0.addWidget(qlabel,2,0,1,1)
-        self.l0.addWidget(self.PCedit,2,1,1,1)
+        qlabel = QLabel("PC: ")
+        qlabel.setStyleSheet("color: white;")
+        self.l0.addWidget(qlabel, 2, 0, 1, 1)
+        self.l0.addWidget(self.PCedit, 2, 1, 1, 1)
         self.comboBox.addItem("PC")
         self.PCedit.returnPressed.connect(self.PCreturn)
 
-        #model = np.load(os.path.join(parent.ops['save_path0'], 'embedding.npy'))
-        #model = np.load('embedding.npy', allow_pickle=True).item()
-        self.isort1 = np.argsort(self.model.embedding[:,0])
+        #model = np.load(os.path.join(parent.ops["save_path0"], "embedding.npy"))
+        #model = np.load("embedding.npy", allow_pickle=True).item()
+        self.isort1 = np.argsort(self.model.embedding[:, 0])
         self.u = self.model.u
         self.v = self.model.v
         self.comboBox.addItem("rastermap")
@@ -625,14 +639,14 @@ def activate(self):
         self.raster = True
         ncells = len(self.parent.stat)
         # cells not in sorting are set to -1
-        self.parent.isort = -1*np.ones((ncells,),dtype=np.int64)
+        self.parent.isort = -1 * np.ones((ncells,), dtype=np.int64)
         nsel = len(self.cells)
         I = np.zeros(nsel)
-        I[self.isort1] = np.arange(nsel).astype('int')
-        self.parent.isort[self.cells] = I #self.isort1
+        I[self.isort1] = np.arange(nsel).astype("int")
+        self.parent.isort[self.cells] = I  #self.isort1
         # set up colors for rastermap
         masks.rastermap_masks(self.parent)
-        b = len(self.parent.color_names)-1
+        b = len(self.parent.color_names) - 1
         self.parent.colorbtns.button(b).setEnabled(True)
         self.parent.colorbtns.button(b).setStyleSheet(self.parent.styleUnpressed)
         self.parent.rastermap = True
@@ -644,45 +658,55 @@ def activate(self):
         self.sortTime.setChecked(False)
 
     def compute_map(self):
-        ops = {'n_components': 1, 'n_X': 100, 'alpha': 1., 'K': 1.,
-                    'nPC': 200, 'constraints': 2, 'annealing': True, 'init': 'pca',
-                    'start_time': 0, 'end_time': -1}
-        self.error=False
-        self.finish=True
+        ops = {
+            "n_components": 1,
+            "n_X": 100,
+            "alpha": 1.,
+            "K": 1.,
+            "nPC": 200,
+            "constraints": 2,
+            "annealing": True,
+            "init": "pca",
+            "start_time": 0,
+            "end_time": -1
+        }
+        self.error = False
+        self.finish = True
         self.mapOn.setEnabled(False)
-        self.tic=time.time()
+        self.tic = time.time()
         try:
-            self.model = Rastermap(n_components=ops['n_components'], n_X=ops['n_X'], nPC=ops['nPC'],
-                          init=ops['init'], alpha=ops['alpha'], K=ops['K'], constraints=ops['constraints'],
-                          annealing=ops['annealing'])
+            self.model = Rastermap(n_components=ops["n_components"], n_X=ops["n_X"],
+                                   nPC=ops["nPC"], init=ops["init"], alpha=ops["alpha"],
+                                   K=ops["K"], constraints=ops["constraints"],
+                                   annealing=ops["annealing"])
             self.model.fit(self.sp)
-            #proc  = {'embedding': model.embedding, 'uv': [model.u, model.v],
-            #         'ops': ops, 'filename': args.S, 'train_time': train_time}
+            #proc  = {"embedding": model.embedding, "uv": [model.u, model.v],
+            #         "ops": ops, "filename": args.S, "train_time": train_time}
             #basename, fname = os.path.split(args.S)
-            #np.save(os.path.join(basename, 'embedding.npy'), proc)
-            print('raster map computed in %3.2f s'%(time.time()-self.tic))
+            #np.save(os.path.join(basename, "embedding.npy"), proc)
+            print("raster map computed in %3.2f s" % (time.time() - self.tic))
             self.activate()
         except:
-            print('Rastermap issue: Interrupted by error (not finished)\n')
-        #self.process.start('python -u -W ignore -m rastermap --S %s --ops %s'%
+            print("Rastermap issue: Interrupted by error (not finished)\n")
+        #self.process.start("python -u -W ignore -m rastermap --S %s --ops %s"%
         #                    (spath, opspath))
 
     def finished(self):
         if self.finish and not self.error:
-            print('raster map computed in %3.2f s'%(time.time()-self.tic))
+            print("raster map computed in %3.2f s" % (time.time() - self.tic))
             self.activate()
         else:
-            sys.stdout.write('Interrupted by error (not finished)\n')
+            sys.stdout.write("Interrupted by error (not finished)\n")
 
     def stdout_write(self):
-        output = str(self.process.readAllStandardOutput(), 'utf-8')
-        #self.logfile = open(os.path.join(self.save_path, 'suite2p/run.log'), 'a')
+        output = str(self.process.readAllStandardOutput(), "utf-8")
+        #self.logfile = open(os.path.join(self.save_path, "suite2p/run.log"), "a")
         sys.stdout.write(output)
         #self.logfile.close()
 
     def stderr_write(self):
-        sys.stdout.write('>>>ERROR<<<\n')
-        output = str(self.process.readAllStandardError(), 'utf-8')
+        sys.stdout.write(">>>ERROR<<<\n")
+        output = str(self.process.readAllStandardError(), "utf-8")
         sys.stdout.write(output)
         self.error = True
         self.finish = False
@@ -695,35 +719,46 @@ def select_cells(self):
             self.parent.ichosen = self.parent.imerge[0]
             self.parent.update_plot()
         else:
-            print('too many cells selected')
+            print("too many cells selected")
 
     def sort_time(self):
         if self.raster:
             if self.sortTime.isChecked():
-                ops = {'n_components': 1, 'n_X': 100, 'alpha': 1., 'K': 1.,
-                            'nPC': 200, 'constraints': 2, 'annealing': True, 'init': 'pca',
-                            'start_time': 0, 'end_time': -1}
-                if not hasattr(self, 'isort2'):
-                    self.model = Rastermap(n_components=ops['n_components'], n_X=ops['n_X'], nPC=ops['nPC'],
-                                  init=ops['init'], alpha=ops['alpha'], K=ops['K'], constraints=ops['constraints'],
-                                  annealing=ops['annealing'])
+                ops = {
+                    "n_components": 1,
+                    "n_X": 100,
+                    "alpha": 1.,
+                    "K": 1.,
+                    "nPC": 200,
+                    "constraints": 2,
+                    "annealing": True,
+                    "init": "pca",
+                    "start_time": 0,
+                    "end_time": -1
+                }
+                if not hasattr(self, "isort2"):
+                    self.model = Rastermap(n_components=ops["n_components"],
+                                           n_X=ops["n_X"], nPC=ops["nPC"],
+                                           init=ops["init"], alpha=ops["alpha"],
+                                           K=ops["K"], constraints=ops["constraints"],
+                                           annealing=ops["annealing"])
                     unorm = (self.u**2).sum(axis=0)**0.5
                     self.model.fit(self.sp.T, u=self.v * unorm, v=self.u / unorm)
-                    self.isort2 = np.argsort(self.model.embedding[:,0])
+                    self.isort2 = np.argsort(self.model.embedding[:, 0])
                 self.tsort = self.isort2.astype(np.int32)
             else:
-                self.tsort = np.arange(0,self.sp.shape[1]).astype(np.int32)
+                self.tsort = np.arange(0, self.sp.shape[1]).astype(np.int32)
             self.neural_sorting(self.comboBox.currentIndex())
 
-    def neural_sorting(self,i):
-        if i==0:
-            self.isort = np.argsort(self.u[:,int(self.PCedit.text())-1])
-        elif i==1:
+    def neural_sorting(self, i):
+        if i == 0:
+            self.isort = np.argsort(self.u[:, int(self.PCedit.text()) - 1])
+        elif i == 1:
             self.isort = self.isort1
-        if i<2:
-            self.spF = gaussian_filter1d(self.sp[np.ix_(self.isort,self.tsort)].T,
-                                        np.minimum(8,np.maximum(1,int(self.sp.shape[0]*0.005))),
-                                        axis=1)
+        if i < 2:
+            self.spF = gaussian_filter1d(
+                self.sp[np.ix_(self.isort, self.tsort)].T,
+                np.minimum(8, np.maximum(1, int(self.sp.shape[0] * 0.005))), axis=1)
             self.spF = self.spF.T
         else:
             self.spF = self.sp
diff --git a/suite2p/io/__init__.py b/suite2p/io/__init__.py
index e84f1dda6..bef701cb8 100644
--- a/suite2p/io/__init__.py
+++ b/suite2p/io/__init__.py
@@ -4,5 +4,5 @@
 from .sbx import sbx_to_binary
 from .tiff import mesoscan_to_binary, ome_to_binary, tiff_to_binary, generate_tiff_filename, save_tiff
 from .nd2 import nd2_to_binary
-from .binary import BinaryFile, BinaryRWFile, BinaryFileCombined
+from .binary import BinaryFile, BinaryFileCombined
 from .server import send_jobs
diff --git a/suite2p/io/binary.py b/suite2p/io/binary.py
index 677f11e16..d92f74417 100644
--- a/suite2p/io/binary.py
+++ b/suite2p/io/binary.py
@@ -4,8 +4,11 @@
 
 import numpy as np
 
-class BinaryRWFile:
-    def __init__(self, Ly: int, Lx: int, filename: str):
+
+class BinaryFile:
+
+    def __init__(self, Ly: int, Lx: int, filename: str, n_frames: int = None,
+                 dtype: str = "int16"):
         """
         Creates/Opens a Suite2p BinaryFile for reading and/or writing image data that acts like numpy array
 
@@ -21,15 +24,23 @@ def __init__(self, Ly: int, Lx: int, filename: str):
         self.Ly = Ly
         self.Lx = Lx
         self.filename = filename
-        if not os.path.exists(filename):
-            self.file = open(filename, mode='w+b')
-        else:
-            self.file = open(filename, mode='r+b')
+        self.dtype = dtype
+        write = (not os.path.exists(self.filename))
+
+        if write and n_frames is None:
+            raise ValueError(
+                "need to provide number of frames n_frames when writing file")
+        elif not write:
+            n_frames = self.n_frames
+        shape = (n_frames, self.Ly, self.Lx)
+        mode = "w+" if write else "r+"
+        self.file = np.memmap(self.filename, mode=mode, dtype=self.dtype, shape=shape)
         self._index = 0
         self._can_read = True
 
     @staticmethod
-    def convert_numpy_file_to_suite2p_binary(from_filename: str, to_filename: str) -> None:
+    def convert_numpy_file_to_suite2p_binary(from_filename: str,
+                                             to_filename: str) -> None:
         """
         Works with npz files, pickled npy files, etc.
 
@@ -50,9 +61,7 @@ def nbytesread(self):
     @property
     def nbytes(self):
         """total number of bytes in the file."""
-        with temporary_pointer(self.file) as f:
-            f.seek(0, 2)
-            return f.tell()
+        return os.path.getsize(self.filename)
 
     @property
     def n_frames(self) -> int:
@@ -90,8 +99,8 @@ def close(self) -> None:
         """
         Closes the file.
         """
-        self.file.close()
-        
+        self.file._mmap.close()
+
     def __enter__(self):
         return self
 
@@ -99,248 +108,15 @@ def __exit__(self, exc_type, exc_val, exc_tb):
         self.close()
 
     def __setitem__(self, *items):
-        frame_indices, data = items
-        self.ix_write(data=data, indices=from_slice(frame_indices))
-        
-    def __getitem__(self, *items):
-        frame_indices, *crop = items
-        if isinstance(frame_indices, int):
-            frames = self.ix(indices=[frame_indices], is_slice=False)
-        elif isinstance(frame_indices, slice):
-            frames = self.ix(indices=from_slice(frame_indices), is_slice=True)
-        else:
-            frames = self.ix(indices=frame_indices, is_slice=False)
-        return frames[(slice(None),) + crop] if crop else frames
-
-    def sampled_mean(self) -> float:
-        """
-        Returns the sampled mean.
-        """
-        n_frames = self.n_frames
-        nsamps = min(n_frames, 1000)
-        inds = np.linspace(0, n_frames, 1+nsamps).astype(np.int64)[:-1]
-        frames = self.ix(indices=inds).astype(np.float32)
-        return frames.mean(axis=0)
-
-    def ix_write(self, data, indices: Sequence[int]):
-        """
-        Writes the frames at index values "indices".
-
-        Parameters
-        ----------
-        indices: int array
-            The frame indices to get, must be a slice
-
-        """
-        i0 = indices[0]
-        batch_size = len(indices)
-        if self._index != i0:
-            self.file.seek(self.nbytesread * (i0 - self._index), 1)
-        self._index = i0 + batch_size
-        self.write(data)  
-
-    def ix(self, indices: Sequence[int], is_slice=False):
-        """
-        Returns the frames at index values "indices".
-
-        Parameters
-        ----------
-        indices: int array
-            The frame indices to get
-
-        is_slice: bool, default False
-            if indices are slice, read slice with "read" function and return
-
-        Returns
-        -------
-        frames: len(indices) x Ly x Lx
-            The requested frames
-        """
-        if not is_slice:
-            frames = np.empty((len(indices), self.Ly, self.Lx), np.int16)
-            # load and bin data
-            with temporary_pointer(self.file) as f:
-                for frame, ixx in zip(frames, indices):
-                    if ixx!=self._index:
-                        f.seek(self.nbytesread * ixx)
-                    buff = f.read(self.nbytesread)
-                    data = np.frombuffer(buff, dtype=np.int16, offset=0)
-                    frame[:] = np.reshape(data, (self.Ly, self.Lx))
-                    #self._index = ixx+1
+        indices, data = items
+        if data.dtype != "int16":
+            self.file[indices] = np.minimum(data, 2**15 - 2).astype("int16")
         else:
-            i0 = indices[0]
-            batch_size = len(indices)
-            if self._index != i0:
-                self.file.seek(self.nbytesread * i0)
-            _, frames = self.read(batch_size=batch_size, dtype=np.int16)
-            self._index = i0 + batch_size
-        
-        return frames
-
-    @property
-    def data(self) -> np.ndarray:
-        """
-        Returns all the frames in the file.
-
-        Returns
-        -------
-        frames: nImg x Ly x Lx
-            The frame data
-        """
-        with temporary_pointer(self.file) as f:
-            return np.fromfile(f, np.int16).reshape(-1, self.Ly, self.Lx)
-
-    def read(self, batch_size=1, dtype=np.float32) -> Optional[Tuple[np.ndarray, np.ndarray]]:
-        """
-        Returns the next frame(s) in the file and its associated indices.
-
-        Parameters
-        ----------
-        batch_size: int
-            The number of frames to read at once.
-        frames: batch_size x Ly x Lx
-            The frame data
-        """
-        if not self._can_read:
-            raise IOError("BinaryFile needs to write before it can read again.")
-        nbytes = self.nbytesread * batch_size
-        buff = self.file.read(nbytes)
-        data = np.frombuffer(buff, dtype=np.int16, offset=0).reshape(-1, self.Ly, self.Lx).astype(dtype)
-        if data.size == 0:
-            return None
-        indices = np.arange(self._index, self._index + data.shape[0])
-        self._index += data.shape[0]
-        return indices, data
-
-    def write(self, data: np.ndarray) -> None:
-        """
-        Writes frame(s) to the file.
-
-        Parameters
-        ----------
-        data: 2D or 3D array
-            The frame(s) to write.  Should be the same width and height as the other frames in the file.
-        """
-        self.file.write(bytearray(np.minimum(data, 2 ** 15 - 2).astype('int16')))
-
-class BinaryFile:
-
-    def __init__(self, Ly: int, Lx: int, read_filename: str, write_filename: Optional[str] = None):
-        """
-        Creates/Opens a Suite2p BinaryFile for reading and writing image data
-
-        Parameters
-        ----------
-        Ly: int
-            The height of each frame
-        Lx: int
-            The width of each frame
-        read_filename: str
-            The filename of the file to read from
-        write_filename: str
-            The filename to write to, if different from the read_filename (optional)
-        """
-        self.Ly = Ly
-        self.Lx = Lx
-        self.read_filename = read_filename
-        self.write_filename = write_filename
-
-        if read_filename == write_filename:
-            self.read_file = open(read_filename, mode='r+b')
-            self.write_file = self.read_file
-        elif read_filename and not write_filename:
-            self.read_file = open(read_filename, mode='rb')
-            self.write_file = write_filename
-        elif read_filename and write_filename and read_filename != write_filename:
-            self.read_file = open(read_filename, mode='rb')
-            self.write_file = open(write_filename, mode='wb')
-        else:
-            raise IOError("Invalid combination of read_file and write_file")
-
-        self._index = 0
-        self._can_read = True
-
-    @staticmethod
-    def convert_numpy_file_to_suite2p_binary(from_filename: str, to_filename: str) -> None:
-        """
-        Works with npz files, pickled npy files, etc.
-
-        Parameters
-        ----------
-        from_filename: str
-            The npy file to convert
-        to_filename: str
-            The binary file that will be created
-        """
-        np.load(from_filename).tofile(to_filename)
-
-    @property
-    def nbytesread(self):
-        """number of bytes per frame (FIXED for given file)"""
-        return np.int64(2 * self.Ly * self.Lx)
-
-    @property
-    def nbytes(self):
-        """total number of bytes in the read_file."""
-        with temporary_pointer(self.read_file) as f:
-            f.seek(0, 2)
-            return f.tell()
-
-    @property
-    def n_frames(self) -> int:
-        """total number of frames in the read_file."""
-        return int(self.nbytes // self.nbytesread)
-
-    @property
-    def shape(self) -> Tuple[int, int, int]:
-        """
-        The dimensions of the data in the file
-
-        Returns
-        -------
-        n_frames: int
-            The number of frames
-        Ly: int
-            The height of each frame
-        Lx: int
-            The width of each frame
-        """
-        return self.n_frames, self.Ly, self.Lx
-
-    @property
-    def size(self) -> int:
-        """
-        Returns the total number of pixels
-
-        Returns
-        -------
-        size: int
-        """
-        return np.prod(np.array(self.shape).astype(np.int64))
-
-    def close(self) -> None:
-        """
-        Closes the file.
-        """
-        self.read_file.close()
-        if self.write_file:
-            self.write_file.close()
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, exc_type, exc_val, exc_tb):
-        self.close()
+            self.file[indices] = data
 
     def __getitem__(self, *items):
-        frame_indices, *crop = items
-        if isinstance(frame_indices, int):
-            frames = self.ix(indices=[frame_indices], is_slice=False)
-        elif isinstance(frame_indices, slice):
-            frames = self.ix(indices=from_slice(frame_indices), is_slice=True)
-        else:
-            frames = self.ix(indices=frame_indices)
-        return frames[(slice(None),) + crop] if crop else frames
+        indices, *crop = items
+        return self.file[indices]
 
     def sampled_mean(self) -> float:
         """
@@ -348,73 +124,10 @@ def sampled_mean(self) -> float:
         """
         n_frames = self.n_frames
         nsamps = min(n_frames, 1000)
-        inds = np.linspace(0, n_frames, 1+nsamps).astype(np.int64)[:-1]
-        frames = self.ix(indices=inds).astype(np.float32)
+        inds = np.linspace(0, n_frames, 1 + nsamps).astype(np.int64)[:-1]
+        frames = self.file[inds].astype(np.float32)
         return frames.mean(axis=0)
 
-    def iter_frames(self, batch_size: int = 1, dtype=np.float32):
-        """
-        Iterates through each set of frames, depending on batch_size, yielding both the frame index and frame data.
-
-        Parameters
-        ---------
-        batch_size: int
-            The number of frames to get at a time
-        dtype: np.dtype
-            The nympy data type that the data should return as
-
-        Yields
-        ------
-        indices: array int
-            The frame indices.
-        data: batch_size x Ly x Lx
-            The frames
-        """
-        while True:
-            results = self.read(batch_size=batch_size, dtype=dtype)
-            if results is None:
-                break
-            indices, data = results
-            yield indices, data
-
-    def ix(self, indices: Sequence[int], is_slice=False):
-        """
-        Returns the frames at index values "indices".
-
-        Parameters
-        ----------
-        indices: int array
-            The frame indices to get
-
-        is_slice: bool, default False
-            if indices are slice, read slice with "read" function and return
-
-        Returns
-        -------
-        frames: len(indices) x Ly x Lx
-            The requested frames
-        """
-        if not is_slice:
-            frames = np.empty((len(indices), self.Ly, self.Lx), np.int16)
-            # load and bin data
-            with temporary_pointer(self.read_file) as f:
-                for frame, ixx in zip(frames, indices):
-                    if ixx!=self._index:
-                        f.seek(self.nbytesread * ixx)
-                    buff = f.read(self.nbytesread)
-                    data = np.frombuffer(buff, dtype=np.int16, offset=0)
-                    frame[:] = np.reshape(data, (self.Ly, self.Lx))
-                    self._index = ixx+1
-        else:
-            i0 = indices[0]
-            batch_size = len(indices)
-            if self._index != i0:
-                self.read_file.seek(self.nbytesread * i0)
-            _, frames = self.read(batch_size=batch_size, dtype=np.int16)
-            self._index = i0 + batch_size
-        
-        return frames
-
     @property
     def data(self) -> np.ndarray:
         """
@@ -422,56 +135,15 @@ def data(self) -> np.ndarray:
 
         Returns
         -------
-        frames: nImg x Ly x Lx
+        frames: n_frames x Ly x Lx
             The frame data
         """
-        with temporary_pointer(self.read_file) as f:
-            return np.fromfile(f, np.int16).reshape(-1, self.Ly, self.Lx)
+        return self.file[:]
 
-    def read(self, batch_size=1, dtype=np.float32) -> Optional[Tuple[np.ndarray, np.ndarray]]:
-        """
-        Returns the next frame(s) in the file and its associated indices.
-
-        Parameters
-        ----------
-        batch_size: int
-            The number of frames to read at once.
-        frames: batch_size x Ly x Lx
-            The frame data
-        """
-        if not self._can_read:
-            raise IOError("BinaryFile needs to write before it can read again.")
-        nbytes = self.nbytesread * batch_size
-        buff = self.read_file.read(nbytes)
-        data = np.frombuffer(buff, dtype=np.int16, offset=0).reshape(-1, self.Ly, self.Lx).astype(dtype)
-        if data.size == 0:
-            return None
-        indices = np.arange(self._index, self._index + data.shape[0])
-        self._index += data.shape[0]
-        if self.read_file is self.write_file:
-            self._can_read = False
-        return indices, data
-
-    def write(self, data: np.ndarray) -> None:
-        """
-        Writes frame(s) to the file.
-
-        Parameters
-        ----------
-        data: 2D or 3D array
-            The frame(s) to write.  Should be the same width and height as the other frames in the file.
-        """
-        if self._can_read and self.read_file is self.write_file:
-            raise IOError("BinaryFile needs to read before it can write again.")
-        if not self.write_file:
-            raise IOError("No write_file specified, writing not possible.")
-        if self.read_file is self.write_file:
-            self.write_file.seek(-2 * data.size, 1)
-            self._can_read = True
-        self.write_file.write(bytearray(np.minimum(data, 2 ** 15 - 2).astype('int16')))
-
-    def bin_movie(self, bin_size: int, x_range: Optional[Tuple[int, int]] = None, y_range: Optional[Tuple[int, int]] = None,
-                  bad_frames: Optional[np.ndarray] = None, reject_threshold: float = 0.5) -> np.ndarray:
+    def bin_movie(self, bin_size: int, x_range: Optional[Tuple[int, int]] = None,
+                  y_range: Optional[Tuple[int, int]] = None,
+                  bad_frames: Optional[np.ndarray] = None,
+                  reject_threshold: float = 0.5) -> np.ndarray:
         """
         Returns binned movie that rejects bad_frames (bool array) and crops to (y_range, x_range).
 
@@ -493,13 +165,14 @@ def bin_movie(self, bin_size: int, x_range: Optional[Tuple[int, int]] = None, y_
             The frames
         """
 
-        good_frames = ~bad_frames if bad_frames is not None else np.ones(self.n_frames, dtype=bool)
+        good_frames = ~bad_frames if bad_frames is not None else np.ones(
+            self.n_frames, dtype=bool)
 
         batch_size = min(np.sum(good_frames), 500)
         batches = []
-        for indices, data in self.iter_frames(batch_size=batch_size):
-            if len(data) != batch_size:
-                break
+        for k in np.arange(0, self.n_frames, batch_size):
+            indices = slice(k, min(k + batch_size, self.n_frames))
+            data = self.file[indices]
 
             if x_range is not None and y_range is not None:
                 data = data[:, slice(*y_range), slice(*x_range)]  # crop
@@ -518,11 +191,12 @@ def bin_movie(self, bin_size: int, x_range: Optional[Tuple[int, int]] = None, y_
 
 def from_slice(s: slice) -> Optional[np.ndarray]:
     """Creates an np.arange() array from a Python slice object.  Helps provide numpy-like slicing interfaces."""
-    return np.arange(s.start, s.stop, s.step) if any([s.start, s.stop, s.step]) else None
+    return np.arange(s.start, s.stop, s.step) if any([s.start, s.stop, s.step
+                                                     ]) else None
 
 
 def binned_mean(mov: np.ndarray, bin_size) -> np.ndarray:
-    """Returns an array with the mean of each time bin (of size 'bin_size')."""
+    """Returns an array with the mean of each time bin (of size "bin_size")."""
     n_frames, Ly, Lx = mov.shape
     mov = mov[:(n_frames // bin_size) * bin_size]
     return mov.reshape(-1, bin_size, Ly, Lx).astype(np.float32).mean(axis=1)
@@ -535,10 +209,11 @@ def temporary_pointer(file):
     yield file
     file.seek(orig_pointer)
 
+
 class BinaryFileCombined:
 
-    def __init__(self, LY: int, LX: int, Ly: np.ndarray, Lx: np.ndarray, 
-                 dy: np.ndarray, dx: np.ndarray, read_filenames: str):
+    def __init__(self, LY: int, LX: int, Ly: np.ndarray, Lx: np.ndarray, dy: np.ndarray,
+                 dx: np.ndarray, read_filenames: str):
         """
         Creates/Opens a Suite2p BinaryFile for reading image data across planes
 
@@ -566,8 +241,15 @@ def __init__(self, LY: int, LX: int, Ly: np.ndarray, Lx: np.ndarray,
         self.dy = dy
         self.dx = dx
         self.read_filenames = read_filenames
-        
-        self.read_files = [open(read_filename, mode='rb') for read_filename in self.read_filenames]
+
+        self.read_files = [
+            BinaryFile(ly, lx, read_filename)
+            for (ly, lx, read_filename) in zip(self.Ly, self.Lx, self.read_filenames)
+        ]
+        n_frames = np.zeros(len(self.read_files))
+        for rf in self.read_files:
+            n_frames[i] = rf.n_frames
+        assert (n_frames == n_frames[0]).sum() == len(self.read_files)
         self._index = 0
         self._can_read = True
 
@@ -584,141 +266,27 @@ def close(self) -> None:
         for n in range(len(self.read_files)):
             self.read_files[n].close()
 
-    @property
-    def nbytesread(self):
-        """number of bytes per frame (FIXED for given file)"""
-        return (2 * self.Ly * self.Lx).astype(np.int64)
-
     @property
     def nbytes(self):
         """total number of bytes in the read_file."""
         nbytes = np.zeros(len(self.read_files), np.int64)
-        for i,read_file in enumerate(self.read_files):
-            with temporary_pointer(read_file) as f:
-                f.seek(0, 2)
-                nbytes[i] = f.tell()
+        for i, read_file in enumerate(self.read_files):
+            nbytes[i] = read_file.nbytes
         return nbytes
 
     @property
     def n_frames(self) -> int:
         """total number of fraames in the read_file."""
-        return int(self.nbytes[0] // self.nbytesread[0])
-
-
-    def read(self, batch_size=1, dtype=np.float32) -> Optional[Tuple[np.ndarray, np.ndarray]]:
-        """
-        Returns the next frame(s) in the file and its associated indices.
-
-        Parameters
-        ----------
-        batch_size: int
-            The number of frames to read at once.
-        frames: batch_size x Ly x Lx
-            The frame data
-        """
-        if not self._can_read:
-            raise IOError("BinaryFile needs to write before it can read again.")
-
-        for n, (nbytesr, read_file) in enumerate(zip(self.nbytesread, self.read_files)):
-            nbytes = nbytesr * batch_size
-            buff = read_file.read(nbytes)
-            data = np.frombuffer(buff, dtype=np.int16, offset=0).reshape(-1, self.Ly[n], self.Lx[n]).astype(dtype)
-            if data.size == 0:
-                return None
-            if n==0:
-                data_all = np.zeros((data.shape[0], self.LY, self.LX), dtype=np.int16)
-            data_all[:, self.dy[n]:self.dy[n]+self.Ly[n], self.dx[n]:self.dx[n]+self.Lx[n]] = data
-            
-        indices = np.arange(self._index, self._index + data.shape[0])
-        self._index += data.shape[0]
-        
-        return indices, data_all
+        return self.read_files[0].n_frames
 
     def __getitem__(self, *items):
-        frame_indices, *crop = items
-        if isinstance(frame_indices, int):
-            frames = self.ix(indices=[frame_indices], is_slice=False)
-        elif isinstance(frame_indices, slice):
-            frames = self.ix(indices=from_slice(frame_indices), is_slice=True)
-        else:
-            frames = self.ix(indices=frame_indices)
-        return frames[(slice(None),) + crop] if crop else frames
-
-
-    def ix(self, indices: Sequence[int], is_slice=False):
-        """
-        Returns the frames at index values "indices".
-
-        Parameters
-        ----------
-        indices: int array
-            The frame indices to get
+        indices, *crop = items
+        data0 = self.read_files[0][indices]
+        data_all = np.zeros((data0.shape[0], self.LY, self.LX), "int16")
+        for n, read_file in enumerate(self.read_files):
+            if n > 0:
+                data0 = self.read_file[indices]
+            data_all[:, self.dy[n]:self.dy[n] + self.Ly[n],
+                     self.dx[n]:self.dx[n] + self.Lx[n]] = data0
 
-        is_slice: bool, default False
-            if indices are slice, read slice with "read" function and return
-
-        Returns
-        -------
-        frames: len(indices) x Ly x Lx
-            The requested frames
-        """
-        for n, (nbytesr, read_file) in enumerate(zip(self.nbytesread, self.read_files)):
-            
-            if not is_slice:
-                frames = np.empty((len(indices), self.Ly[n], self.Lx[n]), np.int16)
-                # load and bin data
-                with temporary_pointer(read_file) as f:
-                    for frame, ixx in zip(frames, indices):
-                        if ixx!=self._index:
-                            f.seek(nbytesr * ixx)
-                        buff = f.read(nbytesr)
-                        data = np.frombuffer(buff, dtype=np.int16, offset=0)
-                        frame[:] = np.reshape(data, (self.Ly[n], self.Lx[n]))
-                        if n==len(self.Ly)-1:
-                            self._index = ixx+1
-            else:
-                i0 = indices[0]
-                batch_size = len(indices)
-                if self._index != i0:
-                    read_file.seek(nbytesr * i0)
-                buff = read_file.read(nbytesr * batch_size)
-                data = np.frombuffer(buff, dtype=np.int16, offset=0)
-                frames = np.reshape(data, (-1, self.Ly[n], self.Lx[n]))
-                if n==len(self.Ly)-1:
-                    self._index = i0 + batch_size
-
-            if frames.size == 0:
-                return None
-            if n==0:
-                data_all = np.zeros((frames.shape[0], self.LY, self.LX), dtype=np.int16)
-            data_all[:, self.dy[n]:self.dy[n]+self.Ly[n], self.dx[n]:self.dx[n]+self.Lx[n]] = frames
-
-            
         return data_all
-
-    def iter_frames(self, batch_size: int = 1, dtype=np.float32):
-        """
-        Iterates through each set of frames, depending on batch_size, yielding both the frame index and frame data.
-
-        Parameters
-        ---------
-        batch_size: int
-            The number of frames to get at a time
-        dtype: np.dtype
-            The nympy data type that the data should return as
-
-        Yields
-        ------
-        indices: array int
-            The frame indices.
-        data: batch_size x Ly x Lx
-            The frames
-        """
-        while True:
-            results = self.read(batch_size=batch_size, dtype=dtype)
-            if results is None:
-                break
-            indices, data = results
-            yield indices, data
-
-
diff --git a/suite2p/io/h5.py b/suite2p/io/h5.py
index f0a685c00..c82edb081 100644
--- a/suite2p/io/h5.py
+++ b/suite2p/io/h5.py
@@ -13,98 +13,107 @@ def h5py_to_binary(ops):
     Parameters
     ----------
     ops : dictionary
-        'nplanes', 'h5_path', 'h5_key', 'save_path', 'save_folder', 'fast_disk',
-        'nchannels', 'keep_movie_raw', 'look_one_level_down'
+        "nplanes", "h5_path", "h5_key", "save_path", "save_folder", "fast_disk",
+        "nchannels", "keep_movie_raw", "look_one_level_down"
 
     Returns
     -------
         ops : dictionary of first plane
-            'Ly', 'Lx', ops['reg_file'] or ops['raw_file'] is created binary
+            "Ly", "Lx", ops["reg_file"] or ops["raw_file"] is created binary
 
     """
     ops1 = init_ops(ops)
 
-    nplanes = ops1[0]['nplanes']
-    nchannels = ops1[0]['nchannels']
+    nplanes = ops1[0]["nplanes"]
+    nchannels = ops1[0]["nchannels"]
 
     # open all binary files for writing
     ops1, h5list, reg_file, reg_file_chan2 = find_files_open_binaries(ops1, True)
     for ops in ops1:
-        if not ops.get('data_path'):
-            ops['data_path'] = [os.path.dirname(ops['h5py'])]
-    ops1[0]['h5list'] = h5list
-    keys = ops1[0]['h5py_key']
+        if not ops.get("data_path"):
+            ops["data_path"] = [os.path.dirname(ops["h5py"])]
+    ops1[0]["h5list"] = h5list
+    keys = ops1[0]["h5py_key"]
     if isinstance(keys, str):
         keys = [keys]
     iall = 0
-    for j in range(ops['nplanes']):
-        ops1[j]['nframes_per_folder'] = np.zeros(len(h5list), np.int32)
+    for j in range(ops["nplanes"]):
+        ops1[j]["nframes_per_folder"] = np.zeros(len(h5list), np.int32)
 
-    for ih5,h5 in enumerate(h5list):
-        with h5py.File(h5, 'r') as f:
+    for ih5, h5 in enumerate(h5list):
+        with h5py.File(h5, "r") as f:
             # if h5py data is 5D or 4D instead of 3D, assume that
-            # data = (nchan x) (nframes x) nplanes x pixels x pixels 
+            # data = (nchan x) (nframes x) nplanes x pixels x pixels
             # 5D/4D data is flattened to process the same way as interleaved data
             for key in keys:
                 hdims = f[key].ndim
                 # keep track of the plane identity of the first frame (channel identity is assumed always 0)
-                ncp = nplanes*nchannels
-                nbatch = ncp * math.ceil(ops1[0]['batch_size'] / ncp)
-                nframes_all = f[key].shape[0] if hdims == 3 else f[key].shape[0] * f[key].shape[1]
+                ncp = nplanes * nchannels
+                nbatch = ncp * math.ceil(ops1[0]["batch_size"] / ncp)
+                nframes_all = f[key].shape[
+                    0] if hdims == 3 else f[key].shape[0] * f[key].shape[1]
                 nbatch = min(nbatch, nframes_all)
-                nfunc = ops['functional_chan'] - 1 if nchannels > 1 else 0
+                nfunc = ops["functional_chan"] - 1 if nchannels > 1 else 0
                 # loop over all tiffs
                 ik = 0
                 while 1:
-                    if hdims==3:
-                        irange = np.arange(ik, min(ik+nbatch, nframes_all), 1)
-                        if irange.size==0:
+                    if hdims == 3:
+                        irange = np.arange(ik, min(ik + nbatch, nframes_all), 1)
+                        if irange.size == 0:
                             break
                         im = f[key][irange, :, :]
                     else:
-                        irange = np.arange(ik/ncp, 
-                                           min(ik/ncp + nbatch/ncp, nframes_all/ncp), 1)
-                        if irange.size==0:
+                        irange = np.arange(
+                            ik / ncp, min(ik / ncp + nbatch / ncp, nframes_all / ncp),
+                            1)
+                        if irange.size == 0:
                             break
-                        im = f[key][irange,...]
-                        if im.ndim==5 and im.shape[0] == nchannels:
-                            im = im.transpose((1,0,2,3,4))
+                        im = f[key][irange, ...]
+                        if im.ndim == 5 and im.shape[0] == nchannels:
+                            im = im.transpose((1, 0, 2, 3, 4))
                         # flatten to frames x pixels x pixels
                         im = np.reshape(im, (-1, im.shape[-2], im.shape[-1]))
                     nframes = im.shape[0]
-                    if type(im[0,0,0]) == np.uint16:
+                    if type(im[0, 0, 0]) == np.uint16:
                         im = im / 2
-                    for j in range(0,nplanes):
-                        if iall==0:
-                            ops1[j]['meanImg'] = np.zeros((im.shape[1],im.shape[2]),np.float32)
-                            if nchannels>1:
-                                ops1[j]['meanImg_chan2'] = np.zeros((im.shape[1],im.shape[2]),np.float32)
-                            ops1[j]['nframes'] = 0
-                        i0 = nchannels * ((j)%nplanes)
-                        im2write = im[np.arange(int(i0)+nfunc, nframes, ncp),:,:].astype(np.int16)
+                    for j in range(0, nplanes):
+                        if iall == 0:
+                            ops1[j]["meanImg"] = np.zeros((im.shape[1], im.shape[2]),
+                                                          np.float32)
+                            if nchannels > 1:
+                                ops1[j]["meanImg_chan2"] = np.zeros(
+                                    (im.shape[1], im.shape[2]), np.float32)
+                            ops1[j]["nframes"] = 0
+                        i0 = nchannels * ((j) % nplanes)
+                        im2write = im[np.arange(int(i0) +
+                                                nfunc, nframes, ncp), :, :].astype(
+                                                    np.int16)
                         reg_file[j].write(bytearray(im2write))
-                        ops1[j]['meanImg'] += im2write.astype(np.float32).sum(axis=0)
-                        if nchannels>1:
-                            im2write = im[np.arange(int(i0)+1-nfunc, nframes, ncp),:,:].astype(np.int16)
+                        ops1[j]["meanImg"] += im2write.astype(np.float32).sum(axis=0)
+                        if nchannels > 1:
+                            im2write = im[np.arange(int(i0) + 1 -
+                                                    nfunc, nframes, ncp), :, :].astype(
+                                                        np.int16)
                             reg_file_chan2[j].write(bytearray(im2write))
-                            ops1[j]['meanImg_chan2'] += im2write.astype(np.float32).sum(axis=0)
-                        ops1[j]['nframes'] += im2write.shape[0]
-                        ops1[j]['nframes_per_folder'][ih5] += im2write.shape[0]
+                            ops1[j]["meanImg_chan2"] += im2write.astype(
+                                np.float32).sum(axis=0)
+                        ops1[j]["nframes"] += im2write.shape[0]
+                        ops1[j]["nframes_per_folder"][ih5] += im2write.shape[0]
                     ik += nframes
                     iall += nframes
 
     # write ops files
-    do_registration = ops1[0]['do_registration']
+    do_registration = ops1[0]["do_registration"]
     for ops in ops1:
-        ops['Ly'] = im2write.shape[1]
-        ops['Lx'] = im2write.shape[2]
+        ops["Ly"] = im2write.shape[1]
+        ops["Lx"] = im2write.shape[2]
         if not do_registration:
-            ops['yrange'] = np.array([0,ops['Ly']])
-            ops['xrange'] = np.array([0,ops['Lx']])
-        ops['meanImg'] /= ops['nframes']
+            ops["yrange"] = np.array([0, ops["Ly"]])
+            ops["xrange"] = np.array([0, ops["Lx"]])
+        ops["meanImg"] /= ops["nframes"]
         if nchannels > 1:
-            ops['meanImg_chan2'] /= ops['nframes']
-        np.save(ops['ops_path'], ops)
+            ops["meanImg_chan2"] /= ops["nframes"]
+        np.save(ops["ops_path"], ops)
     # close all binary files and write ops files
     for j in range(nplanes):
         reg_file[j].close()
diff --git a/suite2p/io/nd2.py b/suite2p/io/nd2.py
index 0546dc8f4..aff0029ef 100644
--- a/suite2p/io/nd2.py
+++ b/suite2p/io/nd2.py
@@ -13,15 +13,15 @@ def nd2_to_binary(ops):
     Parameters
     ----------
     ops: dictionary
-        'nplanes', 'data_path', 'save_path', 'save_folder', 'fast_disk',
-        'nchannels', 'keep_movie_raw', 'look_one_level_down'
+        "nplanes", "data_path", "save_path", "save_folder", "fast_disk",
+        "nchannels", "keep_movie_raw", "look_one_level_down"
 
     Returns
     -------
         ops : dictionary of first plane
-            ops['reg_file'] or ops['raw_file'] is created binary
-            assigns keys 'Ly', 'Lx', 'tiffreader', 'first_tiffs',
-            'nframes', 'meanImg', 'meanImg_chan2'
+            ops["reg_file"] or ops["raw_file"] is created binary
+            assigns keys "Ly", "Lx", "tiffreader", "first_tiffs",
+            "nframes", "meanImg", "meanImg_chan2"
     """
 
     t0 = time.time()
@@ -48,8 +48,7 @@ def nd2_to_binary(ops):
 
         # Sort the dimensions in the order of TZCYX, skipping the missing ones.
         im = nd2_file.asarray().transpose(
-            [nd2_dims[x] for x in valid_dimensions if x in nd2_dims]
-        )
+            [nd2_dims[x] for x in valid_dimensions if x in nd2_dims])
 
         # Expand array to include the missing dimensions.
         for i, dim in enumerate("TZC"):
@@ -82,24 +81,20 @@ def nd2_to_binary(ops):
                 im2write = im_p[:, :, ichan, :, :]
                 for j in range(0, nplanes):
                     if iall == 0:
-                        ops1[j]["meanImg"] = np.zeros(
-                            (im_p.shape[3], im_p.shape[4]), np.float32
-                        )
+                        ops1[j]["meanImg"] = np.zeros((im_p.shape[3], im_p.shape[4]),
+                                                      np.float32)
                         if nchannels > 1:
                             ops1[j]["meanImg_chan2"] = np.zeros(
-                                (im_p.shape[3], im_p.shape[4]), np.float32
-                            )
+                                (im_p.shape[3], im_p.shape[4]), np.float32)
                         ops1[j]["nframes"] = 0
                     if ichan == nfunc:
                         ops1[j]["meanImg"] += np.squeeze(im2mean[j, ichan, :, :])
                         reg_file[j].write(
-                            bytearray(im2write[:, j, :, :].astype("int16"))
-                        )
+                            bytearray(im2write[:, j, :, :].astype("int16")))
                     else:
                         ops1[j]["meanImg_chan2"] += np.squeeze(im2mean[j, ichan, :, :])
                         reg_file_chan2[j].write(
-                            bytearray(im2write[:, j, :, :].astype("int16"))
-                        )
+                            bytearray(im2write[:, j, :, :].astype("int16")))
 
                     ops1[j]["nframes"] += im2write.shape[0]
             ik += nframes
diff --git a/suite2p/io/nwb.py b/suite2p/io/nwb.py
index 785d4ecbe..a0bbc04cf 100644
--- a/suite2p/io/nwb.py
+++ b/suite2p/io/nwb.py
@@ -38,17 +38,17 @@ def nwb_to_binary(ops):
     Parameters
     ----------
     ops: dictionary
-        requires 'nwb_file' key
-        optional keys 'nwb_driver', 'nwb_series'
-        uses 'nplanes', 'save_path', 'save_folder', 'fast_disk',
-        'nchannels', 'keep_movie_raw', 'look_one_level_down'
+        requires "nwb_file" key
+        optional keys "nwb_driver", "nwb_series"
+        uses "nplanes", "save_path", "save_folder", "fast_disk",
+        "nchannels", "keep_movie_raw", "look_one_level_down"
 
     Returns
     -------
         ops : dictionary of first plane
-            ops['reg_file'] or ops['raw_file'] is created binary
-            assigns keys 'Ly', 'Lx', 'tiffreader', 'first_tiffs',
-            'frames_per_folder', 'nframes', 'meanImg', 'meanImg_chan2'
+            ops["reg_file"] or ops["raw_file"] is created binary
+            assigns keys "Ly", "Lx", "tiffreader", "first_tiffs",
+            "frames_per_folder", "nframes", "meanImg", "meanImg_chan2"
 
     """
 
@@ -93,8 +93,7 @@ def nwb_to_binary(ops):
                 raise ValueError("no TwoPhotonSeries in NWB file")
             elif len(TwoPhotonSeries_names) > 1:
                 raise Warning(
-                    "more than one TwoPhotonSeries in NWB file, choosing first one"
-                )
+                    "more than one TwoPhotonSeries in NWB file, choosing first one")
             ops["nwb_series"] = TwoPhotonSeries_names[0]
 
         series = nwbfile.acquisition[ops["nwb_series"]]
@@ -119,9 +118,8 @@ def nwb_to_binary(ops):
             ops["meanImg"] += im.astype(np.float32).sum(axis=0)
 
             if ikend % (batch_size * 4) == 0:
-                print(
-                    "%d frames of binary, time %0.2f sec." % (ikend, time.time() - t0)
-                )
+                print("%d frames of binary, time %0.2f sec." %
+                      (ikend, time.time() - t0))
         gc.collect()
 
     # write ops files
@@ -148,44 +146,38 @@ def read_nwb(fpath):
         # ROIs
         try:
             rois = nwbfile.processing["ophys"]["ImageSegmentation"][
-                "PlaneSegmentation"
-            ]["pixel_mask"]
+                "PlaneSegmentation"]["pixel_mask"]
             multiplane = False
         except Exception:
             rois = nwbfile.processing["ophys"]["ImageSegmentation"][
-                "PlaneSegmentation"
-            ]["voxel_mask"]
+                "PlaneSegmentation"]["voxel_mask"]
             multiplane = True
         stat = []
         for n in range(len(rois)):
             if isinstance(rois[0], np.ndarray):
-                stat.append(
-                    {
-                        "ypix": np.array(
-                            [rois[n][i][0].astype("int") for i in range(len(rois[n]))]
-                        ),
-                        "xpix": np.array(
-                            [rois[n][i][1].astype("int") for i in range(len(rois[n]))]
-                        ),
-                        "lam": np.array([rois[n][i][-1] for i in range(len(rois[n]))]),
-                    }
-                )
+                stat.append({
+                    "ypix":
+                        np.array(
+                            [rois[n][i][0].astype("int") for i in range(len(rois[n]))]),
+                    "xpix":
+                        np.array(
+                            [rois[n][i][1].astype("int") for i in range(len(rois[n]))]),
+                    "lam":
+                        np.array([rois[n][i][-1] for i in range(len(rois[n]))]),
+                })
             else:
-                stat.append(
-                    {
-                        "ypix": rois[n]["x"].astype("int"),
-                        "xpix": rois[n]["y"].astype("int"),
-                        "lam": rois[n]["weight"],
-                    }
-                )
+                stat.append({
+                    "ypix": rois[n]["x"].astype("int"),
+                    "xpix": rois[n]["y"].astype("int"),
+                    "lam": rois[n]["weight"],
+                })
             if multiplane:
-                stat[-1]['iplane'] = int(rois[n][0][-2])
+                stat[-1]["iplane"] = int(rois[n][0][-2])
         ops = default_ops()
 
         if multiplane:
-            nplanes = (
-                np.max(np.array([stat[n]["iplane"] for n in range(len(stat))])) + 1
-            )
+            nplanes = (np.max(np.array([stat[n]["iplane"] for n in range(len(stat))])) +
+                       1)
         else:
             nplanes = 1
         stat = np.array(stat)
@@ -194,18 +186,13 @@ def read_nwb(fpath):
         ops1 = []
         for iplane in range(nplanes):
             ops = default_ops()
-            bg_strs = ['meanImg', 'Vcorr', 'max_proj', 'meanImg_chan2']
-            ops['nchannels'] = 1
+            bg_strs = ["meanImg", "Vcorr", "max_proj", "meanImg_chan2"]
+            ops["nchannels"] = 1
             for bstr in bg_strs:
-                if (
-                    bstr
-                    in nwbfile.processing["ophys"]["Backgrounds_%d" % iplane].images
-                ):
-                    ops[bstr] = np.array(
-                        nwbfile.processing["ophys"]["Backgrounds_%d" % iplane][
-                            bstr
-                        ].data
-                    )
+                if (bstr in nwbfile.processing["ophys"]["Backgrounds_%d" %
+                                                        iplane].images):
+                    ops[bstr] = np.array(nwbfile.processing["ophys"]["Backgrounds_%d" %
+                                                                     iplane][bstr].data)
                     if bstr == "meanImg_chan2":
                         ops["nchannels"] = 2
             ops["Ly"], ops["Lx"] = ops[bg_strs[0]].shape
@@ -215,7 +202,7 @@ def read_nwb(fpath):
             ops["fs"] = nwbfile.acquisition["TwoPhotonSeries"].rate
             ops1.append(ops.copy())
 
-        stat = roi_stats(stat, ops['Ly'], ops['Lx'], ops['aspect'], ops['diameter'])
+        stat = roi_stats(stat, ops["Ly"], ops["Lx"], ops["aspect"], ops["diameter"])
 
         # fluorescence
         ophys = nwbfile.processing["ophys"]
@@ -282,8 +269,8 @@ def get_fluo(name: str) -> np.ndarray:
                     if "meanImg_chan2" in ops:
                         meanImg_chan2[np.ix_(yrange, xrange)] = ops["meanImg_chan2"]
                 for j in np.nonzero(
-                    np.array([stat[n]["iplane"] == k for n in range(len(stat))])
-                )[0]:
+                        np.array([stat[n]["iplane"] == k for n in range(len(stat))
+                                 ]))[0]:
                     stat[j]["xpix"] += ops["dx"]
                     stat[j]["ypix"] += ops["dy"]
                     stat[j]["med"][0] += ops["dy"]
@@ -302,13 +289,11 @@ def get_fluo(name: str) -> np.ndarray:
 def save_nwb(save_folder):
     """convert folder with plane folders to NWB format"""
 
-    plane_folders = natsorted(
-        [
-            Path(f.path)
-            for f in os.scandir(save_folder)
-            if f.is_dir() and f.name[:5] == "plane"
-        ]
-    )
+    plane_folders = natsorted([
+        Path(f.path)
+        for f in os.scandir(save_folder)
+        if f.is_dir() and f.name[:5] == "plane"
+    ])
     ops1 = [
         np.load(f.joinpath("ops.npy"), allow_pickle=True).item() for f in plane_folders
     ]
@@ -382,8 +367,7 @@ def save_nwb(save_folder):
             reference_images=image_series,
         )
         ophys_module = nwbfile.create_processing_module(
-            name="ophys", description="optical physiology processed data"
-        )
+            name="ophys", description="optical physiology processed data")
         ophys_module.add(img_seg)
 
         file_strs = ["F.npy", "Fneu.npy", "spks.npy"]
@@ -399,8 +383,7 @@ def save_nwb(save_folder):
                 if nchannels > 1:
                     for fstr in file_strs_chan2:
                         traces_chan2.append(
-                            np.load(plane_folders[iplane].joinpath(fstr))
-                        )
+                            np.load(plane_folders[iplane].joinpath(fstr)))
                 PlaneCellsIdx = iplane * np.ones(len(iscell))
             else:
                 iscell = np.append(
@@ -411,9 +394,8 @@ def save_nwb(save_folder):
                 for i, fstr in enumerate(file_strs):
                     trace = np.load(os.path.join(ops["save_path"], fstr))
                     if trace.shape[1] < Nfr:
-                        fcat = np.zeros(
-                            (trace.shape[0], Nfr - trace.shape[1]), "float32"
-                        )
+                        fcat = np.zeros((trace.shape[0], Nfr - trace.shape[1]),
+                                        "float32")
                         trace = np.concatenate((trace, fcat), axis=1)
                     traces[i] = np.append(traces[i], trace, axis=0)
                 if nchannels > 1:
@@ -424,28 +406,23 @@ def save_nwb(save_folder):
                             axis=0,
                         )
                 PlaneCellsIdx = np.append(
-                    PlaneCellsIdx, iplane * np.ones(len(iscell) - len(PlaneCellsIdx))
-                )
+                    PlaneCellsIdx, iplane * np.ones(len(iscell) - len(PlaneCellsIdx)))
 
-            stat = np.load(
-                os.path.join(ops["save_path"], "stat.npy"), allow_pickle=True
-            )
+            stat = np.load(os.path.join(ops["save_path"], "stat.npy"),
+                           allow_pickle=True)
             ncells[iplane] = len(stat)
             for n in range(ncells[iplane]):
                 if multiplane:
-                    pixel_mask = np.array(
-                        [
-                            stat[n]["ypix"],
-                            stat[n]["xpix"],
-                            iplane * np.ones(stat[n]["npix"]),
-                            stat[n]["lam"],
-                        ]
-                    )
+                    pixel_mask = np.array([
+                        stat[n]["ypix"],
+                        stat[n]["xpix"],
+                        iplane * np.ones(stat[n]["npix"]),
+                        stat[n]["lam"],
+                    ])
                     ps.add_roi(voxel_mask=pixel_mask.T)
                 else:
                     pixel_mask = np.array(
-                        [stat[n]["ypix"], stat[n]["xpix"], stat[n]["lam"]]
-                    )
+                        [stat[n]["ypix"], stat[n]["xpix"], stat[n]["lam"]])
                     ps.add_roi(pixel_mask=pixel_mask.T)
 
         ps.add_column("iscell", "two columns - iscell & probcell", iscell)
@@ -455,12 +432,9 @@ def save_nwb(save_folder):
             if iplane == 0:
                 rt_region.append(
                     ps.create_roi_table_region(
-                        region=list(
-                            np.arange(0, ncells[iplane]),
-                        ),
+                        region=list(np.arange(0, ncells[iplane]),),
                         description=f"ROIs for plane{int(iplane)}",
-                    )
-                )
+                    ))
             else:
                 rt_region.append(
                     ps.create_roi_table_region(
@@ -468,11 +442,9 @@ def save_nwb(save_folder):
                             np.arange(
                                 np.sum(ncells[:iplane]),
                                 ncells[iplane] + np.sum(ncells[:iplane]),
-                            )
-                        ),
+                            )),
                         description=f"ROIs for plane{int(iplane)}",
-                    )
-                )
+                    ))
 
         # FLUORESCENCE (all are required)
         name_strs = ["Fluorescence", "Neuropil", "Deconvolved"]
@@ -505,9 +477,8 @@ def save_nwb(save_folder):
                     )
 
                     if iplane == 0:
-                        fl = Fluorescence(
-                            roi_response_series=roi_resp_series, name=nstr
-                        )
+                        fl = Fluorescence(roi_response_series=roi_resp_series,
+                                          name=nstr)
                     else:
                         fl.add_roi_response_series(roi_response_series=roi_resp_series)
 
@@ -523,8 +494,8 @@ def save_nwb(save_folder):
                     if bstr == "Vcorr" or bstr == "max_proj":
                         img = np.zeros((ops["Ly"], ops["Lx"]), np.float32)
                         img[
-                            ops["yrange"][0] : ops["yrange"][-1],
-                            ops["xrange"][0] : ops["xrange"][-1],
+                            ops["yrange"][0]:ops["yrange"][-1],
+                            ops["xrange"][0]:ops["xrange"][-1],
                         ] = ops[bstr]
                     else:
                         img = ops[bstr]
@@ -535,4 +506,4 @@ def save_nwb(save_folder):
         with NWBHDF5IO(os.path.join(save_folder, "ophys.nwb"), "w") as fio:
             fio.write(nwbfile)
     else:
-        print('pip install pynwb OR don"t use mesoscope recording')
+        print("pip install pynwb OR don't use mesoscope recording")
diff --git a/suite2p/io/save.py b/suite2p/io/save.py
index 056004794..ee1b0aa5c 100644
--- a/suite2p/io/save.py
+++ b/suite2p/io/save.py
@@ -5,11 +5,13 @@
 import scipy
 import pathlib
 
+
 def save_mat(ops, stat, F, Fneu, spks, iscell, redcell):
     ops_matlab = ops.copy()
-    if ops_matlab.get('date_proc'):
+    if ops_matlab.get("date_proc"):
         try:
-            ops_matlab['date_proc'] = str(datetime.strftime(ops_matlab['date_proc'], "%Y-%m-%d %H:%M:%S.%f"))
+            ops_matlab["date_proc"] = str(
+                datetime.strftime(ops_matlab["date_proc"], "%Y-%m-%d %H:%M:%S.%f"))
         except:
             pass
     for k in ops_matlab.keys():
@@ -19,54 +21,54 @@ def save_mat(ops, stat, F, Fneu, spks, iscell, redcell):
             if isinstance(ops_matlab[k][0], (pathlib.WindowsPath, pathlib.PosixPath)):
                 ops_matlab[k] = [os.fspath(p.absolute()) for p in ops_matlab[k]]
                 print(k, ops_matlab[k])
-                
+
     stat = np.array(stat, dtype=object)
-        
+
     scipy.io.savemat(
-        file_name=os.path.join(ops['save_path'], 'Fall.mat'),
-        mdict={
-            'stat': stat,
-            'ops': ops_matlab,
-            'F': F,
-            'Fneu': Fneu,
-            'spks': spks,
-            'iscell': iscell,
-            'redcell': redcell
-        }
-    )
+        file_name=os.path.join(ops["save_path"], "Fall.mat"), mdict={
+            "stat": stat,
+            "ops": ops_matlab,
+            "F": F,
+            "Fneu": Fneu,
+            "spks": spks,
+            "iscell": iscell,
+            "redcell": redcell
+        })
+
 
 def compute_dydx(ops1):
     ops = ops1[0].copy()
     dx = np.zeros(len(ops1), np.int64)
     dy = np.zeros(len(ops1), np.int64)
-    if ('dx' not in ops) or ('dy' not in ops):
-        Lx = ops['Lx']
-        Ly = ops['Ly']
-        nX = np.ceil(np.sqrt(ops['Ly'] * ops['Lx'] * len(ops1))/ops['Lx'])
+    if ("dx" not in ops) or ("dy" not in ops):
+        Lx = ops["Lx"]
+        Ly = ops["Ly"]
+        nX = np.ceil(np.sqrt(ops["Ly"] * ops["Lx"] * len(ops1)) / ops["Lx"])
         nX = int(nX)
         for j in range(len(ops1)):
-            dx[j] = (j%nX) * Lx
-            dy[j] = int(j/nX) * Ly
+            dx[j] = (j % nX) * Lx
+            dy[j] = int(j / nX) * Ly
     else:
-        dx = np.array([o['dx'] for o in ops1])
-        dy = np.array([o['dy'] for o in ops1])
-        unq = np.unique(np.vstack((dy,dx)), axis=1)
+        dx = np.array([o["dx"] for o in ops1])
+        dy = np.array([o["dy"] for o in ops1])
+        unq = np.unique(np.vstack((dy, dx)), axis=1)
         nrois = unq.shape[1]
         if nrois < len(ops1):
             nplanes = len(ops1) // nrois
-            Lx = np.array([o['Lx'] for o in ops1])
-            Ly = np.array([o['Ly'] for o in ops1])
-            ymax = (dy+Ly).max()
-            xmax = (dx+Lx).max()
-            nX = np.ceil(np.sqrt(ymax * xmax * nplanes)/xmax)
+            Lx = np.array([o["Lx"] for o in ops1])
+            Ly = np.array([o["Ly"] for o in ops1])
+            ymax = (dy + Ly).max()
+            xmax = (dx + Lx).max()
+            nX = np.ceil(np.sqrt(ymax * xmax * nplanes) / xmax)
             nX = int(nX)
-            nY = int(np.ceil(len(ops1)/nX))
+            nY = int(np.ceil(len(ops1) / nX))
             for j in range(nplanes):
                 for k in range(nrois):
-                    dx[j*nrois + k] += (j%nX) * xmax
-                    dy[j*nrois + k] += int(j/nX) * ymax 
+                    dx[j * nrois + k] += (j % nX) * xmax
+                    dy[j * nrois + k] += int(j / nX) * ymax
     return dy, dx
 
+
 def combined(save_folder, save=True):
     """ Combines all the folders in save_folder into a single result file.
 
@@ -76,126 +78,135 @@ def combined(save_folder, save=True):
     Multi-roi recordings are arranged by their dx,dy physical localization.
     Multi-plane / multi-roi recordings are tiled after using dx,dy.
     """
-    plane_folders = natsorted([ f.path for f in os.scandir(save_folder) if f.is_dir() and f.name[:5]=='plane'])
-    ops1 = [np.load(os.path.join(f, 'ops.npy'), allow_pickle=True).item() for f in plane_folders]
+    plane_folders = natsorted([
+        f.path for f in os.scandir(save_folder) if f.is_dir() and f.name[:5] == "plane"
+    ])
+    ops1 = [
+        np.load(os.path.join(f, "ops.npy"), allow_pickle=True).item()
+        for f in plane_folders
+    ]
     dy, dx = compute_dydx(ops1)
-    Ly = np.array([ops['Ly'] for ops in ops1])
-    Lx = np.array([ops['Lx'] for ops in ops1])
+    Ly = np.array([ops["Ly"] for ops in ops1])
+    Lx = np.array([ops["Lx"] for ops in ops1])
     LY = int(np.amax(dy + Ly))
     LX = int(np.amax(dx + Lx))
     meanImg = np.zeros((LY, LX))
     meanImgE = np.zeros((LY, LX))
-    if ops1[0]['nchannels']>1:
+    if ops1[0]["nchannels"] > 1:
         meanImg_chan2 = np.zeros((LY, LX))
-    if any(['meanImg_chan2_corrected' in ops for ops in ops1]):
+    if any(["meanImg_chan2_corrected" in ops for ops in ops1]):
         meanImg_chan2_corrected = np.zeros((LY, LX))
-    if any(['max_proj' in ops for ops in ops1]):
+    if any(["max_proj" in ops for ops in ops1]):
         max_proj = np.zeros((LY, LX))
 
     Vcorr = np.zeros((LY, LX))
-    Nfr = np.amax(np.array([ops['nframes'] for ops in ops1]))
-    ii=0
-    for k,ops in enumerate(ops1):
+    Nfr = np.amax(np.array([ops["nframes"] for ops in ops1]))
+    ii = 0
+    for k, ops in enumerate(ops1):
         fpath = plane_folders[k]
-        if not os.path.exists(os.path.join(fpath,'stat.npy')):
+        if not os.path.exists(os.path.join(fpath, "stat.npy")):
             continue
-        stat0 = np.load(os.path.join(fpath,'stat.npy'), allow_pickle=True)
+        stat0 = np.load(os.path.join(fpath, "stat.npy"), allow_pickle=True)
         xrange = np.arange(dx[k], dx[k] + Lx[k])
         yrange = np.arange(dy[k], dy[k] + Ly[k])
-        meanImg[np.ix_(yrange, xrange)] = ops['meanImg']
-        meanImgE[np.ix_(yrange, xrange)] = ops['meanImgE']
-        if ops['nchannels']>1:
-            if 'meanImg_chan2' in ops:
-                meanImg_chan2[np.ix_(yrange, xrange)] = ops['meanImg_chan2']
-        if 'meanImg_chan2_corrected' in ops:
-            meanImg_chan2_corrected[np.ix_(yrange, xrange)] = ops['meanImg_chan2_corrected']
-
-        xrange = np.arange(dx[k]+ops['xrange'][0],dx[k]+ops['xrange'][-1])
-        yrange = np.arange(dy[k]+ops['yrange'][0],dy[k]+ops['yrange'][-1])
-        Vcorr[np.ix_(yrange, xrange)] = ops['Vcorr']
-        if 'max_proj' in ops:
-            max_proj[np.ix_(yrange, xrange)] = ops['max_proj']
+        meanImg[np.ix_(yrange, xrange)] = ops["meanImg"]
+        meanImgE[np.ix_(yrange, xrange)] = ops["meanImgE"]
+        if ops["nchannels"] > 1:
+            if "meanImg_chan2" in ops:
+                meanImg_chan2[np.ix_(yrange, xrange)] = ops["meanImg_chan2"]
+        if "meanImg_chan2_corrected" in ops:
+            meanImg_chan2_corrected[np.ix_(yrange,
+                                           xrange)] = ops["meanImg_chan2_corrected"]
+
+        xrange = np.arange(dx[k] + ops["xrange"][0], dx[k] + ops["xrange"][-1])
+        yrange = np.arange(dy[k] + ops["yrange"][0], dy[k] + ops["yrange"][-1])
+        Vcorr[np.ix_(yrange, xrange)] = ops["Vcorr"]
+        if "max_proj" in ops:
+            max_proj[np.ix_(yrange, xrange)] = ops["max_proj"]
         for j in range(len(stat0)):
-            stat0[j]['xpix'] += dx[k]
-            stat0[j]['ypix'] += dy[k]
-            stat0[j]['med'][0] += dy[k]
-            stat0[j]['med'][1] += dx[k]
-            stat0[j]['iplane'] = k
-        F0    = np.load(os.path.join(fpath,'F.npy'))
-        Fneu0 = np.load(os.path.join(fpath,'Fneu.npy'))
-        spks0 = np.load(os.path.join(fpath,'spks.npy'))
-        iscell0 = np.load(os.path.join(fpath,'iscell.npy'))
-        if os.path.isfile(os.path.join(fpath,'redcell.npy')):
-            redcell0 = np.load(os.path.join(fpath,'redcell.npy'))
+            stat0[j]["xpix"] += dx[k]
+            stat0[j]["ypix"] += dy[k]
+            stat0[j]["med"][0] += dy[k]
+            stat0[j]["med"][1] += dx[k]
+            stat0[j]["iplane"] = k
+        F0 = np.load(os.path.join(fpath, "F.npy"))
+        Fneu0 = np.load(os.path.join(fpath, "Fneu.npy"))
+        spks0 = np.load(os.path.join(fpath, "spks.npy"))
+        iscell0 = np.load(os.path.join(fpath, "iscell.npy"))
+        if os.path.isfile(os.path.join(fpath, "redcell.npy")):
+            redcell0 = np.load(os.path.join(fpath, "redcell.npy"))
             hasred = True
         else:
             redcell0 = []
             hasred = False
-        nn,nt = F0.shape
-        if nt<Nfr:
-            fcat    = np.zeros((nn,Nfr-nt), 'float32')
+        nn, nt = F0.shape
+        if nt < Nfr:
+            fcat = np.zeros((nn, Nfr - nt), "float32")
             #print(F0.shape)
             #print(fcat.shape)
-            F0      = np.concatenate((F0, fcat), axis=1)
-            spks0   = np.concatenate((spks0, fcat), axis=1)
-            Fneu0   = np.concatenate((Fneu0, fcat), axis=1)
-        if ii==0:
+            F0 = np.concatenate((F0, fcat), axis=1)
+            spks0 = np.concatenate((spks0, fcat), axis=1)
+            Fneu0 = np.concatenate((Fneu0, fcat), axis=1)
+        if ii == 0:
             F, Fneu, spks, stat, iscell, redcell = F0, Fneu0, spks0, stat0, iscell0, redcell0
         else:
-            F    = np.concatenate((F, F0))
+            F = np.concatenate((F, F0))
             Fneu = np.concatenate((Fneu, Fneu0))
             spks = np.concatenate((spks, spks0))
-            stat = np.concatenate((stat,stat0))
-            iscell = np.concatenate((iscell,iscell0))
+            stat = np.concatenate((stat, stat0))
+            iscell = np.concatenate((iscell, iscell0))
             if hasred:
-                redcell = np.concatenate((redcell,redcell0))
-        ii+=1
-        print('appended plane %d to combined view'%k)
-    ops['meanImg']  = meanImg
-    ops['meanImgE'] = meanImgE
-    if ops['nchannels']>1:
-        ops['meanImg_chan2'] = meanImg_chan2
-    if 'meanImg_chan2_corrected' in ops:
-        ops['meanImg_chan2_corrected'] = meanImg_chan2_corrected
-    if 'max_proj' in ops:
-        ops['max_proj'] = max_proj
-    ops['Vcorr'] = Vcorr
-    ops['Ly'] = LY
-    ops['Lx'] = LX
-    ops['xrange'] = [0, ops['Lx']]
-    ops['yrange'] = [0, ops['Ly']]
+                redcell = np.concatenate((redcell, redcell0))
+        ii += 1
+        print("appended plane %d to combined view" % k)
+    ops["meanImg"] = meanImg
+    ops["meanImgE"] = meanImgE
+    if ops["nchannels"] > 1:
+        ops["meanImg_chan2"] = meanImg_chan2
+    if "meanImg_chan2_corrected" in ops:
+        ops["meanImg_chan2_corrected"] = meanImg_chan2_corrected
+    if "max_proj" in ops:
+        ops["max_proj"] = max_proj
+    ops["Vcorr"] = Vcorr
+    ops["Ly"] = LY
+    ops["Lx"] = LX
+    ops["xrange"] = [0, ops["Lx"]]
+    ops["yrange"] = [0, ops["Ly"]]
 
     if save:
-        if len(ops['save_folder']) > 0:
-            fpath = os.path.join(ops['save_path0'], ops['save_folder'], 'combined')
+        if len(ops["save_folder"]) > 0:
+            fpath = os.path.join(ops["save_path0"], ops["save_folder"], "combined")
         else:
-            fpath = os.path.join(ops['save_path0'], 'suite2p', 'combined')
+            fpath = os.path.join(ops["save_path0"], "suite2p", "combined")
     else:
-        fpath = os.path.join(save_folder, 'combined')
-    
+        fpath = os.path.join(save_folder, "combined")
+
     if not os.path.isdir(fpath):
         os.makedirs(fpath)
 
-    ops['save_path'] = fpath
+    ops["save_path"] = fpath
 
     # need to save iscell regardless (required for GUI function)
-    np.save(os.path.join(fpath, 'iscell.npy'), iscell)
+    np.save(os.path.join(fpath, "iscell.npy"), iscell)
     if hasred:
-        np.save(os.path.join(fpath, 'redcell.npy'), redcell)
+        np.save(os.path.join(fpath, "redcell.npy"), redcell)
     else:
         redcell = np.zeros_like(iscell)
 
     if save:
-        np.save(os.path.join(fpath, 'F.npy'), F)
-        np.save(os.path.join(fpath, 'Fneu.npy'), Fneu)
-        np.save(os.path.join(fpath, 'spks.npy'), spks)
-        np.save(os.path.join(fpath, 'ops.npy'), ops)
-        np.save(os.path.join(fpath, 'stat.npy'), stat)
-        
+        np.save(os.path.join(fpath, "F.npy"), F)
+        np.save(os.path.join(fpath, "Fneu.npy"), Fneu)
+        np.save(os.path.join(fpath, "spks.npy"), spks)
+        np.save(os.path.join(fpath, "ops.npy"), ops)
+        np.save(os.path.join(fpath, "stat.npy"), stat)
+
         # save as matlab file
-        if ops.get('save_mat'):
-            matpath = os.path.join(ops['save_path'],'Fall.mat')
+        if ops.get("save_mat"):
+            matpath = os.path.join(ops["save_path"], "Fall.mat")
             save_mat(ops, stat, F, Fneu, spks, iscell, redcell)
-            
-    return stat, ops, F, Fneu, spks, iscell[:,0], iscell[:,1], redcell[:,0], redcell[:,1], hasred
 
+    return stat, ops, F, Fneu, spks, iscell[:,
+                                            0], iscell[:,
+                                                       1], redcell[:,
+                                                                   0], redcell[:,
+                                                                               1], hasred
diff --git a/suite2p/io/sbx.py b/suite2p/io/sbx.py
index 65e11f918..90842f27c 100644
--- a/suite2p/io/sbx.py
+++ b/suite2p/io/sbx.py
@@ -7,125 +7,128 @@
 try:
     from sbxreader import sbx_memmap
 except:
-    print('Could not load the sbx reader, installing with pip.')
+    print("Could not load the sbx reader, installing with pip.")
     from subprocess import call
-    call('pip install sbxreader',shell = True)
+    call("pip install sbxreader", shell=True)
     from sbxreader import sbx_memmap
 
 
-
 def sbx_to_binary(ops, ndeadcols=-1, ndeadrows=0):
     """  finds scanbox files and writes them to binaries
 
     Parameters
     ----------
     ops : dictionary
-        'nplanes', 'data_path', 'save_path', 'save_folder', 'fast_disk',
-        'nchannels', 'keep_movie_raw', 'look_one_level_down'
+        "nplanes", "data_path", "save_path", "save_folder", "fast_disk",
+        "nchannels", "keep_movie_raw", "look_one_level_down"
 
     Returns
     -------
         ops : dictionary of first plane
-            'Ly', 'Lx', ops['reg_file'] or ops['raw_file'] is created binary
+            "Ly", "Lx", ops["reg_file"] or ops["raw_file"] is created binary
 
     """
 
     ops1 = init_ops(ops)
     # the following should be taken from the metadata and not needed but the files are initialized before...
-    nplanes = ops1[0]['nplanes']
-    nchannels = ops1[0]['nchannels']
+    nplanes = ops1[0]["nplanes"]
+    nchannels = ops1[0]["nchannels"]
     # open all binary files for writing
     ops1, sbxlist, reg_file, reg_file_chan2 = find_files_open_binaries(ops1)
     iall = 0
-    for j in range(ops1[0]['nplanes']):
-        ops1[j]['nframes_per_folder'] = np.zeros(len(sbxlist), np.int32)
+    for j in range(ops1[0]["nplanes"]):
+        ops1[j]["nframes_per_folder"] = np.zeros(len(sbxlist), np.int32)
     ik = 0
-    if 'sbx_ndeadcols' in ops1[0].keys():
-        ndeadcols = int(ops1[0]['sbx_ndeadcols'])
-    if 'sbx_ndeadrows' in ops1[0].keys():
-        ndeadrows = int(ops1[0]['sbx_ndeadrows'])
-    
-    if ndeadcols==-1 or ndeadrows==-1:
+    if "sbx_ndeadcols" in ops1[0].keys():
+        ndeadcols = int(ops1[0]["sbx_ndeadcols"])
+    if "sbx_ndeadrows" in ops1[0].keys():
+        ndeadrows = int(ops1[0]["sbx_ndeadrows"])
+
+    if ndeadcols == -1 or ndeadrows == -1:
         # compute dead rows and cols from the first file
         tmpsbx = sbx_memmap(sbxlist[0])
         # do not remove dead rows in non-multiplane mode
         # This number should be different for each plane since the artifact is larger
-        # for larger ETL jumps. 
-        if nplanes > 1 and ndeadrows==-1:
+        # for larger ETL jumps.
+        if nplanes > 1 and ndeadrows == -1:
             colprofile = np.array(np.mean(tmpsbx[0][0][0], axis=1))
             ndeadrows = np.argmax(np.diff(colprofile)) + 1
         else:
             ndeadrows = 0
         # do not remove dead columns in unidirectional scanning mode
-        # do this only if ndeadcols is -1 
-        if tmpsbx.metadata['scanning_mode'] == 'bidirectional' and ndeadcols==-1:
+        # do this only if ndeadcols is -1
+        if tmpsbx.metadata["scanning_mode"] == "bidirectional" and ndeadcols == -1:
             ndeadcols = tmpsbx.ndeadcols
         else:
             ndeadcols = 0
         del tmpsbx
-        print('Removing {0} dead columns while loading sbx data.'.format(ndeadcols))
-        print('Removing {0} dead rows while loading sbx data.'.format(ndeadrows))
+        print("Removing {0} dead columns while loading sbx data.".format(ndeadcols))
+        print("Removing {0} dead rows while loading sbx data.".format(ndeadrows))
 
-    ops1[0]['sbx_ndeadcols'] = ndeadcols
-    ops1[0]['sbx_ndeadrows'] = ndeadrows
-    
-    for ifile,sbxfname in enumerate(sbxlist):
+    ops1[0]["sbx_ndeadcols"] = ndeadcols
+    ops1[0]["sbx_ndeadrows"] = ndeadrows
+
+    for ifile, sbxfname in enumerate(sbxlist):
         f = sbx_memmap(sbxfname)
         nplanes = f.shape[1]
         nchannels = f.shape[2]
         nframes = f.shape[0]
-        iblocks = np.arange(0,nframes,ops1[0]['batch_size'])
+        iblocks = np.arange(0, nframes, ops1[0]["batch_size"])
         if iblocks[-1] < nframes:
-            iblocks = np.append(iblocks,nframes)
+            iblocks = np.append(iblocks, nframes)
 
         # data = nframes x nplanes x nchannels x pixels x pixels
-        if nchannels>1:
-            nfunc = ops1[0]['functional_chan'] - 1
+        if nchannels > 1:
+            nfunc = ops1[0]["functional_chan"] - 1
         else:
             nfunc = 0
         # loop over all frames
-        for ichunk,onset  in enumerate(iblocks[:-1]):
-            offset = iblocks[ichunk+1]
-            im = np.array(f[onset:offset,:,:,ndeadrows:,ndeadcols:])//2
+        for ichunk, onset in enumerate(iblocks[:-1]):
+            offset = iblocks[ichunk + 1]
+            im = np.array(f[onset:offset, :, :, ndeadrows:, ndeadcols:]) // 2
             im = im.astype(np.int16)
-            im2mean = im.mean(axis = 0).astype(np.float32)/len(iblocks) 
+            im2mean = im.mean(axis=0).astype(np.float32) / len(iblocks)
             for ichan in range(nchannels):
                 nframes = im.shape[0]
-                im2write = im[:,:,ichan,:,:]
-                for j in range(0,nplanes):
-                    if iall==0:
-                        ops1[j]['meanImg'] = np.zeros((im.shape[3],im.shape[4]),np.float32)
-                        if nchannels>1:
-                            ops1[j]['meanImg_chan2'] = np.zeros((im.shape[3],im.shape[4]),np.float32)
-                        ops1[j]['nframes'] = 0
+                im2write = im[:, :, ichan, :, :]
+                for j in range(0, nplanes):
+                    if iall == 0:
+                        ops1[j]["meanImg"] = np.zeros((im.shape[3], im.shape[4]),
+                                                      np.float32)
+                        if nchannels > 1:
+                            ops1[j]["meanImg_chan2"] = np.zeros(
+                                (im.shape[3], im.shape[4]), np.float32)
+                        ops1[j]["nframes"] = 0
                     if ichan == nfunc:
-                        ops1[j]['meanImg'] += np.squeeze(im2mean[j,ichan,:,:])
-                        reg_file[j].write(bytearray(im2write[:,j,:,:].astype('int16')))
+                        ops1[j]["meanImg"] += np.squeeze(im2mean[j, ichan, :, :])
+                        reg_file[j].write(
+                            bytearray(im2write[:, j, :, :].astype("int16")))
                     else:
-                        ops1[j]['meanImg_chan2'] += np.squeeze(im2mean[j,ichan,:,:])
-                        reg_file_chan2[j].write(bytearray(im2write[:,j,:,:].astype('int16')))
-                        
-                    ops1[j]['nframes'] += im2write.shape[0]
-                    ops1[j]['nframes_per_folder'][ifile] += im2write.shape[0]
+                        ops1[j]["meanImg_chan2"] += np.squeeze(im2mean[j, ichan, :, :])
+                        reg_file_chan2[j].write(
+                            bytearray(im2write[:, j, :, :].astype("int16")))
+
+                    ops1[j]["nframes"] += im2write.shape[0]
+                    ops1[j]["nframes_per_folder"][ifile] += im2write.shape[0]
             ik += nframes
             iall += nframes
 
     # write ops files
-    do_registration = ops1[0]['do_registration']
-    do_nonrigid = ops1[0]['nonrigid']
+    do_registration = ops1[0]["do_registration"]
+    do_nonrigid = ops1[0]["nonrigid"]
     for ops in ops1:
-        ops['Ly'] = im.shape[3]
-        ops['Lx'] = im.shape[4]
+        ops["Ly"] = im.shape[3]
+        ops["Lx"] = im.shape[4]
         if not do_registration:
-            ops['yrange'] = np.array([0,ops['Ly']])
-            ops['xrange'] = np.array([0,ops['Lx']])
-        #ops['meanImg'] /= ops['nframes']
+            ops["yrange"] = np.array([0, ops["Ly"]])
+            ops["xrange"] = np.array([0, ops["Lx"]])
+        #ops["meanImg"] /= ops["nframes"]
         #if nchannels>1:
-        #    ops['meanImg_chan2'] /= ops['nframes']
-        np.save(ops['ops_path'], ops)
+        #    ops["meanImg_chan2"] /= ops["nframes"]
+        np.save(ops["ops_path"], ops)
     # close all binary files and write ops files
-    for j in range(0,nplanes):
+    for j in range(0, nplanes):
         reg_file[j].close()
-        if nchannels>1:
+        if nchannels > 1:
             reg_file_chan2[j].close()
     return ops1[0]
diff --git a/suite2p/io/server.py b/suite2p/io/server.py
index 3a5ee4b7d..152348630 100644
--- a/suite2p/io/server.py
+++ b/suite2p/io/server.py
@@ -4,15 +4,17 @@
 import paramiko
 import numpy as np
 
+
 def unix_path(path):
-    return str(path).replace(os.sep, '/')
+    return str(path).replace(os.sep, "/")
+
 
-def ssh_connect(host, username, password,verbose=True):
+def ssh_connect(host, username, password, verbose=True):
     """ from paramiko example """
-    i=0
+    i = 0
     while True:
         if verbose:
-            print("Trying to connect to %s (attempt %i/30)" % (host, i+1))
+            print("Trying to connect to %s (attempt %i/30)" % (host, i + 1))
         try:
             ssh = paramiko.SSHClient()
             ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
@@ -33,14 +35,9 @@ def ssh_connect(host, username, password,verbose=True):
             sys.exit(1)
     return ssh
 
-def send_jobs(save_folder,
-         host=None, 
-         username=None, 
-         password=None, 
-         server_root=None, 
-         local_root=None,
-         n_cores=8):
 
+def send_jobs(save_folder, host=None, username=None, password=None, server_root=None,
+              local_root=None, n_cores=8):
     """ send each plane to compute on server separately
 
     add your own host, username, password and path on server 
@@ -49,92 +46,95 @@ def send_jobs(save_folder,
     """
 
     if host is None:
-        raise Exception('No server specified, please edit suite2p/io/server.py')
-    
+        raise Exception("No server specified, please edit suite2p/io/server.py")
+
     # server_root is different from where you created the binaries, which is local_root
     nparts = len(Path(local_root).parts)
     # e.g. if server is Z:/path on local computer, and server_root+path on remote, then nparts=1
-    save_folder_server =  Path(*Path(save_folder).parts[nparts:])
+    save_folder_server = Path(*Path(save_folder).parts[nparts:])
     save_folder_server = Path(server_root) / save_folder_server
     save_path0_server = Path(*Path(save_folder_server).parts[:-1])
     save_folder_name = Path(save_folder).parts[-1]
-    print('save path on server: ', unix_path(save_path0_server))
-    ssh = ssh_connect(host, username, password)    
+    print("save path on server: ", unix_path(save_path0_server))
+    ssh = ssh_connect(host, username, password)
 
     # create bash file in home directory to run
-    run_script = Path.home().joinpath('.suite2p/run_script.sh')
+    run_script = Path.home().joinpath(".suite2p/run_script.sh")
     if run_script.exists():
         os.remove(run_script)
-    with open(run_script, 'x', newline='') as f:
-        f.write('#!/bin/bash\n')    
+    with open(run_script, "x", newline="") as f:
+        f.write("#!/bin/bash\n")
         # server specific commands to activate python
-        f.write('source ~/add_anaconda.sh\n')
-        f.write('eval $(~/anaconda4/bin/conda shell.bash hook)\n')
-        # activate suite2p environment 
-        f.write('source activate suite2p\n')
+        f.write("source ~/add_anaconda.sh\n")
+        f.write("eval $(~/anaconda4/bin/conda shell.bash hook)\n")
+        # activate suite2p environment
+        f.write("source activate suite2p\n")
         # run suite2p single plane command with ops as argument
         f.write('python -m suite2p --single_plane --ops "$@"')
 
-    ssh.exec_command('rm ~/run_script.sh')
-    ssh.exec_command('chmod 777 ~/')
-    ftp_client=ssh.open_sftp()
-    ftp_client.put(run_script, 'run_script.sh')
-    ssh.exec_command('chmod 777 run_script.sh')
+    ssh.exec_command("rm ~/run_script.sh")
+    ssh.exec_command("chmod 777 ~/")
+    ftp_client = ssh.open_sftp()
+    ftp_client.put(run_script, "run_script.sh")
+    ssh.exec_command("chmod 777 run_script.sh")
 
-    pdirs = natsorted(glob.glob(save_folder + '/*/'))
+    pdirs = natsorted(glob.glob(save_folder + "/*/"))
     for k, pdir in enumerate(pdirs):
         ipl = int(Path(pdir).parts[-1][5:])
-        print('>>>>>>>>>> PLANE %d <<<<<<<<<'%ipl)
-        ops_path_orig = pdir + 'ops.npy'
+        print(">>>>>>>>>> PLANE %d <<<<<<<<<" % ipl)
+        ops_path_orig = pdir + "ops.npy"
         op = np.load(ops_path_orig, allow_pickle=True).item()
-        fast_disk_orig = Path(op['fast_disk'])
+        fast_disk_orig = Path(op["fast_disk"])
 
         ## change paths
-        op['save_path0'] = unix_path(save_path0_server)
-        op['save_folder'] = save_folder_name
-        save_path = save_path0_server / save_folder_name / ('plane%d'%ipl)
-        op['save_path'] = unix_path(save_path)
-        op['fast_disk'] = unix_path(save_path)
-        op['ops_path'] = unix_path(save_path / 'ops.npy')
-        print(op['ops_path'])
+        op["save_path0"] = unix_path(save_path0_server)
+        op["save_folder"] = save_folder_name
+        save_path = save_path0_server / save_folder_name / ("plane%d" % ipl)
+        op["save_path"] = unix_path(save_path)
+        op["fast_disk"] = unix_path(save_path)
+        op["ops_path"] = unix_path(save_path / "ops.npy")
+        print(op["ops_path"])
         ## move binary files to server if needed
         # check if file structure needs to be created on remote server
         copy = False
         try:
-            ftp_client.stat(op['save_path'])
+            ftp_client.stat(op["save_path"])
         except IOError:
-            print('copying files')
-            ftp_client.mkdir(op['save_path'])
+            print("copying files")
+            ftp_client.mkdir(op["save_path"])
             copy = True
-        op['reg_file'] = unix_path(save_path / 'data.bin')
-        if 'raw_file' in op:
-            op['raw_file'] = unix_path(save_path / 'data_raw.bin')
+        op["reg_file"] = unix_path(save_path / "data.bin")
+        if "raw_file" in op:
+            op["raw_file"] = unix_path(save_path / "data_raw.bin")
             if copy:
-                ftp_client.put(fast_disk_orig / 'data_raw.bin', op['raw_file'])
-            if 'raw_file_chan2' in op:
-                op['raw_file_chan2'] = unix_path(save_path / 'data_chan2_raw.bin')
+                ftp_client.put(fast_disk_orig / "data_raw.bin", op["raw_file"])
+            if "raw_file_chan2" in op:
+                op["raw_file_chan2"] = unix_path(save_path / "data_chan2_raw.bin")
                 if copy:
-                    ftp_client.put(fast_disk_orig / 'data_raw_chan2.bin', op['raw_file_chan2'])
+                    ftp_client.put(fast_disk_orig / "data_raw_chan2.bin",
+                                   op["raw_file_chan2"])
         else:
             if copy:
-                ftp_client.put(fast_disk_orig / 'data.bin', op['reg_file'])
-            if 'reg_file_chan2' in op:
-                op['reg_file_chan2'] = unix_path(save_path / 'data_chan2.bin')
+                ftp_client.put(fast_disk_orig / "data.bin", op["reg_file"])
+            if "reg_file_chan2" in op:
+                op["reg_file_chan2"] = unix_path(save_path / "data_chan2.bin")
                 if copy:
-                    ftp_client.put(fast_disk_orig / 'data_chan2.bin', op['reg_file_chan2'])
-        
+                    ftp_client.put(fast_disk_orig / "data_chan2.bin",
+                                   op["reg_file_chan2"])
+
         # save final version of ops and send to server
         np.save(ops_path_orig, op)
         if copy:
-            print('copying ops')
-            ftp_client.put(ops_path_orig, op['ops_path'])
+            print("copying ops")
+            ftp_client.put(ops_path_orig, op["ops_path"])
 
         # run plane (server-specific command)
-        run_command = '''bsub -n %d -J test_s2p%d -R"select[avx512]" -o out%d.txt "~/run_script.sh '%s' > log%d.txt"'''%(n_cores, ipl, ipl, op['ops_path'], ipl)
+        run_command = '''bsub -n %d -J test_s2p%d -R"select[avx512]" -o out%d.txt "~/run_script.sh "%s" > log%d.txt''' % (
+            n_cores, ipl, ipl, op["ops_path"], ipl)
         stdin, stdout, stderr = ssh.exec_command(run_command)
         print(stdout.readlines()[0])
-    
+
     ftp_client.close()
-    
+
     print("Command done, closing SSH connection")
     ssh.close()
diff --git a/suite2p/io/tiff.py b/suite2p/io/tiff.py
index 2eba63309..174501d1b 100644
--- a/suite2p/io/tiff.py
+++ b/suite2p/io/tiff.py
@@ -6,15 +6,20 @@
 import time
 from typing import Union, Tuple, Optional
 
-
 import numpy as np
-from ScanImageTiffReader import ScanImageTiffReader
 from tifffile import imread, TiffFile, TiffWriter
 
 from . import utils
 
+try:
+    from ScanImageTiffReader import ScanImageTiffReader
+    HAS_SCANIMAGE = True
+except ImportError:
+    HAS_SCANIMAGE = False
+
 
-def generate_tiff_filename(functional_chan: int, align_by_chan: int, save_path: str, k: int, ichan: bool) -> str:
+def generate_tiff_filename(functional_chan: int, align_by_chan: int, save_path: str,
+                           k: int, ichan: bool) -> str:
     """
     Calculates a suite2p tiff filename from different parameters.
 
@@ -37,21 +42,21 @@ def generate_tiff_filename(functional_chan: int, align_by_chan: int, save_path:
     """
     if ichan:
         if functional_chan == align_by_chan:
-            tifroot = os.path.join(save_path, 'reg_tif')
+            tifroot = os.path.join(save_path, "reg_tif")
             wchan = 0
         else:
-            tifroot = os.path.join(save_path, 'reg_tif_chan2')
+            tifroot = os.path.join(save_path, "reg_tif_chan2")
             wchan = 1
     else:
         if functional_chan == align_by_chan:
-            tifroot = os.path.join(save_path, 'reg_tif_chan2')
+            tifroot = os.path.join(save_path, "reg_tif_chan2")
             wchan = 1
         else:
-            tifroot = os.path.join(save_path, 'reg_tif')
+            tifroot = os.path.join(save_path, "reg_tif")
             wchan = 0
     if not os.path.isdir(tifroot):
         os.makedirs(tifroot)
-    fname = 'file%0.3d_chan%d.tif'%(k,wchan)
+    fname = "file%0.3d_chan%d.tif" % (k, wchan)
     fname = os.path.join(tifroot, fname)
     return fname
 
@@ -73,8 +78,9 @@ def save_tiff(mov: np.ndarray, fname: str) -> None:
             tif.write(frame)
 
 
-def open_tiff(file: str, sktiff: bool) -> Tuple[Union[TiffFile, ScanImageTiffReader], int]:
-    """ Returns image and its length from tiff file with either ScanImageTiffReader or tifffile, based on 'sktiff'"""
+def open_tiff(file: str,
+              sktiff: bool) -> Tuple[Union[TiffFile, ScanImageTiffReader], int]:
+    """ Returns image and its length from tiff file with either ScanImageTiffReader or tifffile, based on "sktiff" """
     if sktiff:
         tif = TiffFile(file)
         Ltif = len(tif.pages)
@@ -86,13 +92,21 @@ def open_tiff(file: str, sktiff: bool) -> Tuple[Union[TiffFile, ScanImageTiffRea
 
 def use_sktiff_reader(tiff_filename, batch_size: Optional[int] = None) -> bool:
     """Returns False if ScanImageTiffReader works on the tiff file, else True (in which case use tifffile)."""
-    try:
-        with ScanImageTiffReader(tiff_filename) as tif:
-            tif.data() if len(tif.shape()) < 3 else tif.data(beg=0, end=np.minimum(batch_size, tif.shape()[0] - 1))
-        return False
-    except:
-        print('NOTE: ScanImageTiffReader not working for this tiff type, using tifffile')
-        return True
+    if HAS_SCANIMAGE:
+        try:
+            with ScanImageTiffReader(tiff_filename) as tif:
+                tif.data() if len(tif.shape()) < 3 else tif.data(
+                    beg=0, end=np.minimum(batch_size,
+                                          tif.shape()[0] - 1))
+            return False
+        except:
+            print(
+                "NOTE: ScanImageTiffReader not working for this tiff type, using tifffile"
+            )
+            return True
+    else:
+        print("NOTE: ScanImageTiffReader not installed, using tifffile")
+
 
 def tiff_to_binary(ops):
     """  finds tiff files and writes them to binaries
@@ -100,41 +114,42 @@ def tiff_to_binary(ops):
     Parameters
     ----------
     ops : dictionary
-        'nplanes', 'data_path', 'save_path', 'save_folder', 'fast_disk', 'nchannels', 'keep_movie_raw', 'look_one_level_down'
+        "nplanes", "data_path", "save_path", "save_folder", "fast_disk", "nchannels", "keep_movie_raw", "look_one_level_down"
 
     Returns
     -------
         ops : dictionary of first plane
-            ops['reg_file'] or ops['raw_file'] is created binary
-            assigns keys 'Ly', 'Lx', 'tiffreader', 'first_tiffs',
-            'frames_per_folder', 'nframes', 'meanImg', 'meanImg_chan2'
+            ops["reg_file"] or ops["raw_file"] is created binary
+            assigns keys "Ly", "Lx", "tiffreader", "first_tiffs",
+            "frames_per_folder", "nframes", "meanImg", "meanImg_chan2"
 
     """
 
-    t0=time.time()
+    t0 = time.time()
     # copy ops to list where each element is ops for each plane
     ops1 = utils.init_ops(ops)
-    nplanes = ops1[0]['nplanes']
-    nchannels = ops1[0]['nchannels']
+    nplanes = ops1[0]["nplanes"]
+    nchannels = ops1[0]["nchannels"]
 
     # open all binary files for writing
     # look for tiffs in all requested folders
     ops1, fs, reg_file, reg_file_chan2 = utils.find_files_open_binaries(ops1, False)
     ops = ops1[0]
     # try tiff readers
-    use_sktiff = True if ops['force_sktiff'] else use_sktiff_reader(fs[0], batch_size=ops1[0].get('batch_size'))
-    
-    batch_size = ops['batch_size']
-    batch_size = nplanes*nchannels*math.ceil(batch_size/(nplanes*nchannels))
+    use_sktiff = True if ops["force_sktiff"] else use_sktiff_reader(
+        fs[0], batch_size=ops1[0].get("batch_size"))
+
+    batch_size = ops["batch_size"]
+    batch_size = nplanes * nchannels * math.ceil(batch_size / (nplanes * nchannels))
 
     # loop over all tiffs
     which_folder = -1
-    ntotal=0
+    ntotal = 0
     for ik, file in enumerate(fs):
         # open tiff
         tif, Ltif = open_tiff(file, use_sktiff)
         # keep track of the plane identity of the first frame (channel identity is assumed always 0)
-        if ops['first_tiffs'][ik]:
+        if ops["first_tiffs"][ik]:
             which_folder += 1
             iplane = 0
         ix = 0
@@ -149,7 +164,7 @@ def tiff_to_binary(ops):
             elif Ltif == 1:
                 im = tif.data()
             else:
-                im = tif.data(beg=ix, end=ix+nfr)
+                im = tif.data(beg=ix, end=ix + nfr)
 
             # for single-page tiffs, add 1st dim
             if len(im.shape) < 3:
@@ -162,117 +177,121 @@ def tiff_to_binary(ops):
                 im = (im // 2).astype(np.int16)
             elif im.dtype.type != np.int16:
                 im = im.astype(np.int16)
-            
+
             if im.shape[0] > nfr:
                 im = im[:nfr, :, :]
             nframes = im.shape[0]
-            for j in range(0,nplanes):
-                if ik==0 and ix==0:
-                    ops1[j]['nframes'] = 0
-                    ops1[j]['frames_per_file'] = np.zeros((len(fs),), dtype=int)
-                    ops1[j]['meanImg'] = np.zeros((im.shape[1], im.shape[2]), np.float32)
-                    if nchannels>1:
-                        ops1[j]['meanImg_chan2'] = np.zeros((im.shape[1], im.shape[2]), np.float32)
-                i0 = nchannels * ((iplane+j)%nplanes)
-                if nchannels>1:
-                    nfunc = ops['functional_chan']-1
+            for j in range(0, nplanes):
+                if ik == 0 and ix == 0:
+                    ops1[j]["nframes"] = 0
+                    ops1[j]["frames_per_file"] = np.zeros((len(fs),), dtype=int)
+                    ops1[j]["meanImg"] = np.zeros((im.shape[1], im.shape[2]),
+                                                  np.float32)
+                    if nchannels > 1:
+                        ops1[j]["meanImg_chan2"] = np.zeros((im.shape[1], im.shape[2]),
+                                                            np.float32)
+                i0 = nchannels * ((iplane + j) % nplanes)
+                if nchannels > 1:
+                    nfunc = ops["functional_chan"] - 1
                 else:
                     nfunc = 0
-                im2write = im[int(i0)+nfunc:nframes:nplanes*nchannels]
+                im2write = im[int(i0) + nfunc:nframes:nplanes * nchannels]
 
                 reg_file[j].write(bytearray(im2write))
-                ops1[j]['meanImg'] += im2write.astype(np.float32).sum(axis=0)
-                ops1[j]['nframes'] += im2write.shape[0]
-                ops1[j]['frames_per_file'][ik] += im2write.shape[0]
-                ops1[j]['frames_per_folder'][which_folder] += im2write.shape[0]
-                #print(ops1[j]['frames_per_folder'][which_folder])
-                if nchannels>1:
-                    im2write = im[int(i0)+1-nfunc:nframes:nplanes*nchannels]
+                ops1[j]["meanImg"] += im2write.astype(np.float32).sum(axis=0)
+                ops1[j]["nframes"] += im2write.shape[0]
+                ops1[j]["frames_per_file"][ik] += im2write.shape[0]
+                ops1[j]["frames_per_folder"][which_folder] += im2write.shape[0]
+                #print(ops1[j]["frames_per_folder"][which_folder])
+                if nchannels > 1:
+                    im2write = im[int(i0) + 1 - nfunc:nframes:nplanes * nchannels]
                     reg_file_chan2[j].write(bytearray(im2write))
-                    ops1[j]['meanImg_chan2'] += im2write.mean(axis=0)
-
-
-            iplane = (iplane-nframes/nchannels)%nplanes
-            ix+=nframes
-            ntotal+=nframes
-            if ntotal%(batch_size*4)==0:
-                print('%d frames of binary, time %0.2f sec.'%(ntotal,time.time()-t0))
+                    ops1[j]["meanImg_chan2"] += im2write.mean(axis=0)
+
+            iplane = (iplane - nframes / nchannels) % nplanes
+            ix += nframes
+            ntotal += nframes
+            if ntotal % (batch_size * 4) == 0:
+                print("%d frames of binary, time %0.2f sec." %
+                      (ntotal, time.time() - t0))
         gc.collect()
     # write ops files
-    do_registration = ops['do_registration']
+    do_registration = ops["do_registration"]
     for ops in ops1:
-        ops['Ly'],ops['Lx'] = ops['meanImg'].shape
-        ops['yrange'] = np.array([0,ops['Ly']])
-        ops['xrange'] = np.array([0,ops['Lx']])
-        ops['meanImg'] /= ops['nframes']
-        if nchannels>1:
-            ops['meanImg_chan2'] /= ops['nframes']
-        np.save(ops['ops_path'], ops)
+        ops["Ly"], ops["Lx"] = ops["meanImg"].shape
+        ops["yrange"] = np.array([0, ops["Ly"]])
+        ops["xrange"] = np.array([0, ops["Lx"]])
+        ops["meanImg"] /= ops["nframes"]
+        if nchannels > 1:
+            ops["meanImg_chan2"] /= ops["nframes"]
+        np.save(ops["ops_path"], ops)
     # close all binary files and write ops files
-    for j in range(0,nplanes):
+    for j in range(0, nplanes):
         reg_file[j].close()
-        if nchannels>1:
+        if nchannels > 1:
             reg_file_chan2[j].close()
     return ops1[0]
 
+
 def mesoscan_to_binary(ops):
     """ finds mesoscope tiff files and writes them to binaries
 
     Parameters
     ----------
     ops : dictionary
-        'nplanes', 'data_path', 'save_path', 'save_folder', 'fast_disk',
-        'nchannels', 'keep_movie_raw', 'look_one_level_down', 'lines', 'dx', 'dy'
+        "nplanes", "data_path", "save_path", "save_folder", "fast_disk",
+        "nchannels", "keep_movie_raw", "look_one_level_down", "lines", "dx", "dy"
 
     Returns
     -------
         ops : dictionary of first plane
-            ops['reg_file'] or ops['raw_file'] is created binary
-            assigns keys 'Ly', 'Lx', 'tiffreader', 'first_tiffs', 'frames_per_folder',
-            'nframes', 'meanImg', 'meanImg_chan2'
+            ops["reg_file"] or ops["raw_file"] is created binary
+            assigns keys "Ly", "Lx", "tiffreader", "first_tiffs", "frames_per_folder",
+            "nframes", "meanImg", "meanImg_chan2"
 
     """
     t0 = time.time()
-    if 'lines' not in ops:
-        fpath = os.path.join(ops['data_path'][0], '*json')
+    if "lines" not in ops:
+        fpath = os.path.join(ops["data_path"][0], "*json")
         fs = glob.glob(fpath)
-        with open(fs[0], 'r') as f:
+        with open(fs[0], "r") as f:
             opsj = json.load(f)
-        if 'nrois' in opsj:
-            ops['nrois'] = opsj['nrois']
-            ops['nplanes'] = opsj['nplanes']
-            ops['dy'] = opsj['dy']
-            ops['dx'] = opsj['dx']
-            ops['fs'] = opsj['fs']
-        elif 'nplanes' in opsj and 'lines' in opsj:
-            ops['nrois'] = opsj['nplanes']
-            ops['nplanes'] = 1
+        if "nrois" in opsj:
+            ops["nrois"] = opsj["nrois"]
+            ops["nplanes"] = opsj["nplanes"]
+            ops["dy"] = opsj["dy"]
+            ops["dx"] = opsj["dx"]
+            ops["fs"] = opsj["fs"]
+        elif "nplanes" in opsj and "lines" in opsj:
+            ops["nrois"] = opsj["nplanes"]
+            ops["nplanes"] = 1
         else:
-            ops['nplanes'] = len(opsj)
-        ops['lines'] = opsj['lines']
+            ops["nplanes"] = len(opsj)
+        ops["lines"] = opsj["lines"]
     else:
-        ops['nrois'] = len(ops['lines'])
-    nplanes = ops['nplanes']
+        ops["nrois"] = len(ops["lines"])
+    nplanes = ops["nplanes"]
 
-    print("NOTE: nplanes %d nrois %d => ops['nplanes'] = %d"%(nplanes,ops['nrois'],ops['nrois']*nplanes))
+    print("NOTE: nplanes %d nrois %d => ops['nplanes'] = %d" %
+          (nplanes, ops["nrois"], ops["nrois"] * nplanes))
     # multiply lines across planes
-    lines = ops['lines'].copy()
-    dy = ops['dy'].copy()
-    dx = ops['dx'].copy()
-    ops['lines'] = [None] * nplanes * ops['nrois']
-    ops['dy'] = [None] * nplanes * ops['nrois']
-    ops['dx'] = [None] * nplanes * ops['nrois']
-    ops['iplane'] = np.zeros((nplanes * ops['nrois'],), np.int32)
-    for n in range(ops['nrois']):
-        ops['lines'][n::ops['nrois']] = [lines[n]] * nplanes
-        ops['dy'][n::ops['nrois']] = [dy[n]] * nplanes
-        ops['dx'][n::ops['nrois']] = [dx[n]] * nplanes
-        ops['iplane'][n::ops['nrois']] = np.arange(0, nplanes, 1, int)
-    ops['nplanes'] = nplanes * ops['nrois']
+    lines = ops["lines"].copy()
+    dy = ops["dy"].copy()
+    dx = ops["dx"].copy()
+    ops["lines"] = [None] * nplanes * ops["nrois"]
+    ops["dy"] = [None] * nplanes * ops["nrois"]
+    ops["dx"] = [None] * nplanes * ops["nrois"]
+    ops["iplane"] = np.zeros((nplanes * ops["nrois"],), np.int32)
+    for n in range(ops["nrois"]):
+        ops["lines"][n::ops["nrois"]] = [lines[n]] * nplanes
+        ops["dy"][n::ops["nrois"]] = [dy[n]] * nplanes
+        ops["dx"][n::ops["nrois"]] = [dx[n]] * nplanes
+        ops["iplane"][n::ops["nrois"]] = np.arange(0, nplanes, 1, int)
+    ops["nplanes"] = nplanes * ops["nrois"]
     ops1 = utils.init_ops(ops)
 
-    # this shouldn't make it here
-    if 'lines' not in ops:
+    # this shouldn"t make it here
+    if "lines" not in ops:
         for j in range(len(ops1)):
             ops1[j] = {**ops1[j], **opsj[j]}.copy()
 
@@ -281,19 +300,20 @@ def mesoscan_to_binary(ops):
     ops1, fs, reg_file, reg_file_chan2 = utils.find_files_open_binaries(ops1, False)
     ops = ops1[0]
 
-    nchannels = ops1[0]['nchannels']
-    batch_size = ops['batch_size']
+    nchannels = ops1[0]["nchannels"]
+    batch_size = ops["batch_size"]
 
-    # which tiff reader works for user's tiffs
-    use_sktiff = True if ops['force_sktiff'] else use_sktiff_reader(fs[0], batch_size=ops1[0].get('batch_size'))
+    # which tiff reader works for user"s tiffs
+    use_sktiff = True if ops["force_sktiff"] else use_sktiff_reader(
+        fs[0], batch_size=ops1[0].get("batch_size"))
 
     # loop over all tiffs
     which_folder = -1
-    ntotal=0
+    ntotal = 0
     for ik, file in enumerate(fs):
         # open tiff
         tif, Ltif = open_tiff(file, use_sktiff)
-        if ops['first_tiffs'][ik]:
+        if ops["first_tiffs"][ik]:
             which_folder += 1
             iplane = 0
         ix = 0
@@ -302,68 +322,74 @@ def mesoscan_to_binary(ops):
                 break
             nfr = min(Ltif - ix, batch_size)
             if use_sktiff:
-                im = imread(file, key = range(ix, ix + nfr))
+                im = imread(file, key=range(ix, ix + nfr))
             else:
-                if Ltif==1:
+                if Ltif == 1:
                     im = tif.data()
                 else:
-                    im = tif.data(beg=ix, end=ix+nfr)
-            if im.size==0:
+                    im = tif.data(beg=ix, end=ix + nfr)
+            if im.size == 0:
                 break
 
-            if len(im.shape)<3:
+            if len(im.shape) < 3:
                 im = np.expand_dims(im, axis=0)
 
             if im.shape[0] > nfr:
                 im = im[:nfr, :, :]
             nframes = im.shape[0]
 
-            for j in range(0, ops['nplanes']):
-                jlines = np.array(ops1[j]['lines']).astype(np.int32)
-                jplane = ops1[j]['iplane']
-                if ik==0 and ix==0:
-                    ops1[j]['meanImg'] = np.zeros((len(jlines), im.shape[2]), np.float32)
-                    if nchannels>1:
-                        ops1[j]['meanImg_chan2'] = np.zeros((len(jlines), im.shape[2]), np.float32)
-                    ops1[j]['nframes'] = 0
-                i0 = nchannels * ((iplane+jplane)%nplanes)
-                if nchannels>1:
-                    nfunc = ops['functional_chan']-1
+            for j in range(0, ops["nplanes"]):
+                jlines = np.array(ops1[j]["lines"]).astype(np.int32)
+                jplane = ops1[j]["iplane"]
+                if ik == 0 and ix == 0:
+                    ops1[j]["meanImg"] = np.zeros((len(jlines), im.shape[2]),
+                                                  np.float32)
+                    if nchannels > 1:
+                        ops1[j]["meanImg_chan2"] = np.zeros((len(jlines), im.shape[2]),
+                                                            np.float32)
+                    ops1[j]["nframes"] = 0
+                i0 = nchannels * ((iplane + jplane) % nplanes)
+                if nchannels > 1:
+                    nfunc = ops["functional_chan"] - 1
                 else:
                     nfunc = 0
                 #frange = np.arange(int(i0)+nfunc, nframes, nplanes*nchannels)
-                im2write = im[int(i0)+nfunc:nframes:nplanes*nchannels, jlines[0]:(jlines[-1]+1), :]
+                im2write = im[int(i0) + nfunc:nframes:nplanes * nchannels,
+                              jlines[0]:(jlines[-1] + 1), :]
                 #im2write = im[np.ix_(frange, jlines, np.arange(0,im.shape[2],1,int))]
-                ops1[j]['meanImg'] += im2write.astype(np.float32).sum(axis=0)
+                ops1[j]["meanImg"] += im2write.astype(np.float32).sum(axis=0)
                 reg_file[j].write(bytearray(im2write))
-                ops1[j]['nframes'] += im2write.shape[0]
-                ops1[j]['frames_per_folder'][which_folder] += im2write.shape[0]
-                if nchannels>1:
-                    frange = np.arange(int(i0)+1-nfunc, nframes, nplanes*nchannels)
-                    im2write = im[np.ix_(frange, jlines, np.arange(0,im.shape[2],1,int))]
+                ops1[j]["nframes"] += im2write.shape[0]
+                ops1[j]["frames_per_folder"][which_folder] += im2write.shape[0]
+                if nchannels > 1:
+                    frange = np.arange(
+                        int(i0) + 1 - nfunc, nframes, nplanes * nchannels)
+                    im2write = im[np.ix_(frange, jlines,
+                                         np.arange(0, im.shape[2], 1, int))]
                     reg_file_chan2[j].write(bytearray(im2write))
-                    ops1[j]['meanImg_chan2'] += im2write.astype(np.float32).sum(axis=0)
-            iplane = (iplane-nframes/nchannels)%nplanes
-            ix+=nframes
-            ntotal+=nframes
-            if ops1[0]['nframes']%(batch_size*4)==0:
-                print('%d frames of binary, time %0.2f sec.'%(ops1[0]['nframes'],time.time()-t0))
+                    ops1[j]["meanImg_chan2"] += im2write.astype(np.float32).sum(axis=0)
+            iplane = (iplane - nframes / nchannels) % nplanes
+            ix += nframes
+            ntotal += nframes
+            if ops1[0]["nframes"] % (batch_size * 4) == 0:
+                print("%d frames of binary, time %0.2f sec." %
+                      (ops1[0]["nframes"], time.time() - t0))
         gc.collect()
     # write ops files
-    do_registration = ops['do_registration']
+    do_registration = ops["do_registration"]
     for ops in ops1:
-        ops['Ly'],ops['Lx'] = ops['meanImg'].shape
+        ops["Ly"], ops["Lx"] = ops["meanImg"].shape
         if not do_registration:
-            ops['yrange'] = np.array([0,ops['Ly']])
-            ops['xrange'] = np.array([0,ops['Lx']])
-        ops['meanImg'] /= ops['nframes']
-        if nchannels>1:
-            ops['meanImg_chan2'] /= ops['nframes']
-        np.save(ops['ops_path'], ops)
+            ops["yrange"] = np.array([0, ops["Ly"]])
+            ops["xrange"] = np.array([0, ops["Lx"]])
+        ops["meanImg"] /= ops["nframes"]
+        if nchannels > 1:
+            ops["meanImg_chan2"] /= ops["nframes"]
+        np.save(ops["ops_path"], ops)
     # close all binary files and write ops files
-    for j in range(0,ops['nplanes']):
+    for j in range(0, ops["nplanes"]):
         reg_file[j].close()
-        if nchannels>1:
+        if nchannels > 1:
             reg_file_chan2[j].close()
     return ops1[0]
 
@@ -371,7 +397,7 @@ def mesoscan_to_binary(ops):
 def ome_to_binary(ops):
     """
     converts ome.tiff to *.bin file for non-interleaved red channel recordings
-    assumes SINGLE-PAGE tiffs where first channel has string 'Ch1'
+    assumes SINGLE-PAGE tiffs where first channel has string "Ch1"
     and also SINGLE FOLDER
 
     Parameters
@@ -382,14 +408,14 @@ def ome_to_binary(ops):
     Returns
     -------
     ops : dictionary of first plane
-        creates binaries ops['reg_file']
+        creates binaries ops["reg_file"]
         assigns keys: tiffreader, first_tiffs, frames_per_folder, nframes, meanImg, meanImg_chan2
     """
     t0 = time.time()
 
     # copy ops to list where each element is ops for each plane
     ops1 = utils.init_ops(ops)
-    nplanes = ops1[0]['nplanes']
+    nplanes = ops1[0]["nplanes"]
 
     # open all binary files for writing and look for tiffs in all requested folders
     ops1, fs, reg_file, reg_file_chan2 = utils.find_files_open_binaries(ops1, False)
@@ -397,93 +423,93 @@ def ome_to_binary(ops):
 
     fs_Ch1, fs_Ch2 = [], []
     for f in fs:
-        if f.find('Ch1')>-1:
-            if ops['functional_chan'] == 1:
+        if f.find("Ch1") > -1:
+            if ops["functional_chan"] == 1:
                 fs_Ch1.append(f)
             else:
                 fs_Ch2.append(f)
         else:
-            if ops['functional_chan'] == 1:
+            if ops["functional_chan"] == 1:
                 fs_Ch2.append(f)
             else:
                 fs_Ch1.append(f)
 
-    if len(fs_Ch2)==0:
-        ops1[0]['nchannels'] = 1
-    nchannels = ops1[0]['nchannels']
+    if len(fs_Ch2) == 0:
+        ops1[0]["nchannels"] = 1
+    nchannels = ops1[0]["nchannels"]
 
     # loop over all tiffs
     with ScanImageTiffReader(fs_Ch1[0]) as tif:
         im0 = tif.data()
-    
+
     for ops1_0 in ops1:
-        ops1_0['nframes'] = 0
-        ops1_0['frames_per_folder'][0] = 0
-        ops1_0['meanImg'] = np.zeros(im0.shape, np.float32)
+        ops1_0["nframes"] = 0
+        ops1_0["frames_per_folder"][0] = 0
+        ops1_0["meanImg"] = np.zeros(im0.shape, np.float32)
         if nchannels > 1:
-            ops1_0['meanImg_chan2'] = np.zeros(im0.shape, np.float32)
+            ops1_0["meanImg_chan2"] = np.zeros(im0.shape, np.float32)
 
-    bruker_bidirectional = ops.get('bruker_bidirectional', False)
+    bruker_bidirectional = ops.get("bruker_bidirectional", False)
     iplanes = np.arange(0, nplanes)
     if not bruker_bidirectional:
-        iplanes = np.tile(iplanes[np.newaxis, :], 
-                          int(np.ceil(len(fs_Ch1)/nplanes))).flatten()
+        iplanes = np.tile(iplanes[np.newaxis, :],
+                          int(np.ceil(len(fs_Ch1) / nplanes))).flatten()
         iplanes = iplanes[:len(fs_Ch1)]
     else:
         iplanes = np.hstack((iplanes, iplanes[::-1]))
-        iplanes = np.tile(iplanes[np.newaxis, :], 
-                          int(np.ceil(len(fs_Ch1)/(2*nplanes)))).flatten()
+        iplanes = np.tile(iplanes[np.newaxis, :],
+                          int(np.ceil(len(fs_Ch1) / (2 * nplanes)))).flatten()
         iplanes = iplanes[:len(fs_Ch1)]
-        
+
     for ik, file in enumerate(fs_Ch1):
         # read tiff
         with ScanImageTiffReader(file) as tif:
             im = tif.data()
         if im.dtype.type == np.uint16:
-            im = (im // 2)  
+            im = (im // 2)
         im = im.astype(np.int16)
 
         # write to binary
         ix = iplanes[ik]
-        ops1[ix]['nframes'] += 1
-        ops1[ix]['frames_per_folder'][0] += 1
-        ops1[ix]['meanImg'] += im.astype(np.float32)
+        ops1[ix]["nframes"] += 1
+        ops1[ix]["frames_per_folder"][0] += 1
+        ops1[ix]["meanImg"] += im.astype(np.float32)
         reg_file[ix].write(bytearray(im))
         gc.collect()
-        
+
         if ik % 1000 == 0:
-            print('%d frames of binary, time %0.2f sec.' % (ik, time.time() - t0))
-    
+            print("%d frames of binary, time %0.2f sec." % (ik, time.time() - t0))
+
     if nchannels > 1:
         for ik, file in enumerate(fs_Ch2):
             with ScanImageTiffReader(file) as tif:
                 im = tif.data()
             if im.dtype.type == np.uint16:
                 im = (im // 2)
-                
+
             im = im.astype(np.int16)
             ix = iplanes[ik]
-            ops1[ix]['meanImg_chan2'] += im.astype(np.float32)
+            ops1[ix]["meanImg_chan2"] += im.astype(np.float32)
             reg_file_chan2[ix].write(bytearray(im))
             gc.collect()
 
             if ik % 1000 == 0:
-                print('%d frames of binary, time %0.2f sec.' % (ik, time.time() - t0))
+                print("%d frames of binary, time %0.2f sec." % (ik, time.time() - t0))
 
     # write ops files
-    do_registration = ops['do_registration']
+    do_registration = ops["do_registration"]
     for ops in ops1:
-        ops['Ly'], ops['Lx'] = im0.shape
+        ops["Ly"], ops["Lx"] = im0.shape
         if not do_registration:
-            ops['yrange'] = np.array([0,ops['Ly']])
-            ops['xrange'] = np.array([0,ops['Lx']])
-        ops['meanImg'] /= ops['nframes']
-        if nchannels>1:
-            ops['meanImg_chan2'] /= ops['nframes']
-        np.save(ops['ops_path'], ops)
+            ops["yrange"] = np.array([0, ops["Ly"]])
+            ops["xrange"] = np.array([0, ops["Lx"]])
+        ops["meanImg"] /= ops["nframes"]
+        if nchannels > 1:
+            ops["meanImg_chan2"] /= ops["nframes"]
+        np.save(ops["ops_path"], ops)
     # close all binary files and write ops files
-    for j in range(0,nplanes):
+    for j in range(0, nplanes):
         reg_file[j].close()
-        if nchannels>1:
+        if nchannels > 1:
             reg_file_chan2[j].close()
     return ops1[0]
diff --git a/suite2p/io/utils.py b/suite2p/io/utils.py
index 8a8b678ab..42786f7d4 100644
--- a/suite2p/io/utils.py
+++ b/suite2p/io/utils.py
@@ -6,59 +6,60 @@
 from natsort import natsorted
 
 
-def search_for_ext(rootdir, extension = 'tif', look_one_level_down=False):
+def search_for_ext(rootdir, extension="tif", look_one_level_down=False):
     filepaths = []
     if os.path.isdir(rootdir):
         # search root dir
-        tmp = glob.glob(os.path.join(rootdir,'*.'+extension))
+        tmp = glob.glob(os.path.join(rootdir, "*." + extension))
         if len(tmp):
             filepaths.extend([t for t in natsorted(tmp)])
         # search one level down
         if look_one_level_down:
             dirs = natsorted(os.listdir(rootdir))
             for d in dirs:
-                if os.path.isdir(os.path.join(rootdir,d)):
-                    tmp = glob.glob(os.path.join(rootdir, d, '*.'+extension))
+                if os.path.isdir(os.path.join(rootdir, d)):
+                    tmp = glob.glob(os.path.join(rootdir, d, "*." + extension))
                     if len(tmp):
                         filepaths.extend([t for t in natsorted(tmp)])
     if len(filepaths):
         return filepaths
     else:
-        raise OSError('Could not find files, check path [{0}]'.format(rootdir))
+        raise OSError("Could not find files, check path [{0}]".format(rootdir))
+
 
 def get_sbx_list(ops):
     """ make list of scanbox files to process
-    if ops['subfolders'], then all tiffs ops['data_path'][0] / ops['subfolders'] / *.sbx
-    if ops['look_one_level_down'], then all tiffs in all folders + one level down
+    if ops["subfolders"], then all tiffs ops["data_path"][0] / ops["subfolders"] / *.sbx
+    if ops["look_one_level_down"], then all tiffs in all folders + one level down
     TODO: Implement "tiff_list" functionality
     """
-    froot = ops['data_path']
+    froot = ops["data_path"]
     # use a user-specified list of tiffs
-    if len(froot)==1:
-        if 'subfolders' in ops and len(ops['subfolders'])>0:
+    if len(froot) == 1:
+        if "subfolders" in ops and len(ops["subfolders"]) > 0:
             fold_list = []
-            for folder_down in ops['subfolders']:
+            for folder_down in ops["subfolders"]:
                 fold = os.path.join(froot[0], folder_down)
                 fold_list.append(fold)
         else:
-            fold_list = ops['data_path']
+            fold_list = ops["data_path"]
     else:
         fold_list = froot
     fsall = []
-    for k,fld in enumerate(fold_list):
-        fs = search_for_ext(fld,
-                            extension = 'sbx',
-                            look_one_level_down = ops['look_one_level_down'])
+    for k, fld in enumerate(fold_list):
+        fs = search_for_ext(fld, extension="sbx",
+                            look_one_level_down=ops["look_one_level_down"])
         fsall.extend(fs)
-    if len(fsall)==0:
+    if len(fsall) == 0:
         print(fold_list)
-        raise Exception('No files, check path.')
+        raise Exception("No files, check path.")
     else:
-        print('** Found %d sbx - converting to binary **'%(len(fsall)))
+        print("** Found %d sbx - converting to binary **" % (len(fsall)))
     return fsall, ops
 
+
 def list_h5(ops):
-    froot = os.path.dirname(ops['h5py'])
+    froot = os.path.dirname(ops["h5py"])
     lpath = os.path.join(froot, "*.h5")
     fs = natsorted(glob.glob(lpath))
     lpath = os.path.join(froot, "*.hdf5")
@@ -66,6 +67,7 @@ def list_h5(ops):
     fs.extend(fs2)
     return fs
 
+
 def list_files(froot, look_one_level_down, exts):
     """ get list of files with exts in folder froot + one level down maybe
     """
@@ -75,10 +77,10 @@ def list_files(froot, look_one_level_down, exts):
         fs.extend(glob.glob(lpath))
     fs = natsorted(set(fs))
     if len(fs) > 0:
-        first_tiffs = np.zeros((len(fs),), 'bool')
+        first_tiffs = np.zeros((len(fs),), "bool")
         first_tiffs[0] = True
     else:
-        first_tiffs = np.zeros(0, 'bool')
+        first_tiffs = np.zeros(0, "bool")
     lfs = len(fs)
     if look_one_level_down:
         fdir = natsorted(glob.glob(os.path.join(froot, "*/")))
@@ -90,98 +92,98 @@ def list_files(froot, look_one_level_down, exts):
             fsnew = natsorted(set(fsnew))
             if len(fsnew) > 0:
                 fs.extend(fsnew)
-                first_tiffs = np.append(first_tiffs, np.zeros((len(fsnew),), 'bool'))
+                first_tiffs = np.append(first_tiffs, np.zeros((len(fsnew),), "bool"))
                 first_tiffs[lfs] = True
                 lfs = len(fs)
     return fs, first_tiffs
 
+
 def get_h5_list(ops):
     """ make list of h5 files to process
-    if ops['look_one_level_down'], then all h5's in all folders + one level down
+    if ops["look_one_level_down"], then all h5"s in all folders + one level down
     """
-    froot = ops['data_path']
-    fold_list = ops['data_path']
+    froot = ops["data_path"]
+    fold_list = ops["data_path"]
     fsall = []
     nfs = 0
     first_tiffs = []
-    for k,fld in enumerate(fold_list):
-        fs, ftiffs = list_files(fld, ops['look_one_level_down'],
-                                ["*.h5", "*.hdf5"])
+    for k, fld in enumerate(fold_list):
+        fs, ftiffs = list_files(fld, ops["look_one_level_down"], 
+                                ["*.h5", "*.hdf5", "*.mesc"])
         fsall.extend(fs)
         first_tiffs.extend(list(ftiffs))
-    if len(fs)==0:
-        print('Could not find any h5 files')
-        raise Exception('no h5s')
+    if len(fs) == 0:
+        print("Could not find any h5 files")
+        raise Exception("no h5s")
     else:
-        ops['first_tiffs'] = np.array(first_tiffs).astype('bool')
-        print('** Found %d h5 files - converting to binary **'%(len(fsall)))
-        #print('Found %d tifs'%(len(fsall)))
+        ops["first_tiffs"] = np.array(first_tiffs).astype("bool")
+        print("** Found %d h5 files - converting to binary **" % (len(fsall)))
+        #print("Found %d tifs"%(len(fsall)))
     return fsall, ops
 
 
 def get_tif_list(ops):
     """ make list of tiffs to process
-    if ops['subfolders'], then all tiffs ops['data_path'][0] / ops['subfolders'] / *.tif
-    if ops['look_one_level_down'], then all tiffs in all folders + one level down
-    if ops['tiff_list'], then ops['data_path'][0] / ops['tiff_list'] ONLY
+    if ops["subfolders"], then all tiffs ops["data_path"][0] / ops["subfolders"] / *.tif
+    if ops["look_one_level_down"], then all tiffs in all folders + one level down
+    if ops["tiff_list"], then ops["data_path"][0] / ops["tiff_list"] ONLY
     """
-    froot = ops['data_path']
+    froot = ops["data_path"]
     # use a user-specified list of tiffs
-    if 'tiff_list' in ops:
+    if "tiff_list" in ops:
         fsall = []
-        for tif in ops['tiff_list']:
+        for tif in ops["tiff_list"]:
             fsall.append(os.path.join(froot[0], tif))
-        ops['first_tiffs'] = np.zeros((len(fsall),), dtype='bool')
-        ops['first_tiffs'][0] = True
-        print('** Found %d tifs - converting to binary **'%(len(fsall)))
+        ops["first_tiffs"] = np.zeros((len(fsall),), dtype="bool")
+        ops["first_tiffs"][0] = True
+        print("** Found %d tifs - converting to binary **" % (len(fsall)))
     else:
-        if len(froot)==1:
-            if 'subfolders' in ops and len(ops['subfolders'])>0:
+        if len(froot) == 1:
+            if "subfolders" in ops and len(ops["subfolders"]) > 0:
                 fold_list = []
-                for folder_down in ops['subfolders']:
+                for folder_down in ops["subfolders"]:
                     fold = os.path.join(froot[0], folder_down)
                     fold_list.append(fold)
             else:
-                fold_list = ops['data_path']
+                fold_list = ops["data_path"]
         else:
             fold_list = froot
         fsall = []
         nfs = 0
         first_tiffs = []
-        for k,fld in enumerate(fold_list):
-            fs, ftiffs = list_files(fld, ops['look_one_level_down'],
+        for k, fld in enumerate(fold_list):
+            fs, ftiffs = list_files(fld, ops["look_one_level_down"],
                                     ["*.tif", "*.tiff", "*.TIF", "*.TIFF"])
             fsall.extend(fs)
             first_tiffs.extend(list(ftiffs))
-        if len(fsall)==0:
-            print('Could not find any tiffs')
-            raise Exception('no tiffs')
+        if len(fsall) == 0:
+            print("Could not find any tiffs")
+            raise Exception("no tiffs")
         else:
-            ops['first_tiffs'] = np.array(first_tiffs).astype('bool')
-            print('** Found %d tifs - converting to binary **'%(len(fsall)))
+            ops["first_tiffs"] = np.array(first_tiffs).astype("bool")
+            print("** Found %d tifs - converting to binary **" % (len(fsall)))
     return fsall, ops
 
 
 def get_nd2_list(ops):
     """ make list of nd2 files to process
-    if ops['look_one_level_down'], then all nd2's in all folders + one level down
+    if ops["look_one_level_down"], then all nd2"s in all folders + one level down
     """
-    froot = ops['data_path']
-    fold_list = ops['data_path']
+    froot = ops["data_path"]
+    fold_list = ops["data_path"]
     fsall = []
     nfs = 0
     first_tiffs = []
-    for k,fld in enumerate(fold_list):
-        fs, ftiffs = list_files(fld, ops['look_one_level_down'],
-                                ["*.nd2"])
+    for k, fld in enumerate(fold_list):
+        fs, ftiffs = list_files(fld, ops["look_one_level_down"], ["*.nd2"])
         fsall.extend(fs)
         first_tiffs.extend(list(ftiffs))
-    if len(fs)==0:
-        print('Could not find any nd2 files')
-        raise Exception('no nd2s')
+    if len(fs) == 0:
+        print("Could not find any nd2 files")
+        raise Exception("no nd2s")
     else:
-        ops['first_tiffs'] = np.array(first_tiffs).astype('bool')
-        print('** Found %d nd2 files - converting to binary **'%(len(fsall)))
+        ops["first_tiffs"] = np.array(first_tiffs).astype("bool")
+        print("** Found %d nd2 files - converting to binary **" % (len(fsall)))
     return fsall, ops
 
 
@@ -191,68 +193,67 @@ def find_files_open_binaries(ops1, ish5=False):
     Parameters
     ----------
     ops1 : list of dictionaries
-        'keep_movie_raw', 'data_path', 'look_one_level_down', 'reg_file'...
+        "keep_movie_raw", "data_path", "look_one_level_down", "reg_file"...
 
     Returns
     -------
         ops1 : list of dictionaries
-            adds fields 'filelist', 'first_tiffs', opens binaries
+            adds fields "filelist", "first_tiffs", opens binaries
 
     """
 
     reg_file = []
-    reg_file_chan2=[]
-
+    reg_file_chan2 = []
 
     for ops in ops1:
-        nchannels = ops['nchannels']
-        if 'keep_movie_raw' in ops and ops['keep_movie_raw']:
-            reg_file.append(open(ops['raw_file'], 'wb'))
-            if nchannels>1:
-                reg_file_chan2.append(open(ops['raw_file_chan2'], 'wb'))
+        nchannels = ops["nchannels"]
+        if "keep_movie_raw" in ops and ops["keep_movie_raw"]:
+            reg_file.append(open(ops["raw_file"], "wb"))
+            if nchannels > 1:
+                reg_file_chan2.append(open(ops["raw_file_chan2"], "wb"))
         else:
-            reg_file.append(open(ops['reg_file'], 'wb'))
-            if nchannels>1:
-                reg_file_chan2.append(open(ops['reg_file_chan2'], 'wb'))
+            reg_file.append(open(ops["reg_file"], "wb"))
+            if nchannels > 1:
+                reg_file_chan2.append(open(ops["reg_file_chan2"], "wb"))
 
-        if 'input_format' in ops.keys():
-            input_format = ops['input_format']
+        if "input_format" in ops.keys():
+            input_format = ops["input_format"]
         else:
-            input_format = 'tif'
+            input_format = "tif"
     if ish5:
-        input_format = 'h5'
+        input_format = "h5"
     print(input_format)
-    if input_format == 'h5':
-        if len(ops1[0]['data_path'])>0:
+    if input_format == "h5":
+        if len(ops1[0]["data_path"]) > 0:
             fs, ops2 = get_h5_list(ops1[0])
-            print('NOTE: using a list of h5 files:')
+            print("NOTE: using a list of h5 files:")
             print(fs)
-        # find h5's
+        # find h5"s
         else:
-            if ops1[0]['look_one_level_down']:
+            if ops1[0]["look_one_level_down"]:
                 fs = list_h5(ops1[0])
-                print('NOTE: using a list of h5 files:')
+                print("NOTE: using a list of h5 files:")
                 print(fs)
             else:
-                fs = [ops1[0]['h5py']]
-    elif input_format == 'sbx':
+                fs = [ops1[0]["h5py"]]
+    elif input_format == "sbx":
         # find sbx
         fs, ops2 = get_sbx_list(ops1[0])
-        print('Scanbox files:')
-        print('\n'.join(fs))
-    elif input_format == 'nd2':
+        print("Scanbox files:")
+        print("\n".join(fs))
+    elif input_format == "nd2":
         # find nd2s
         fs, ops2 = get_nd2_list(ops1[0])
-        print('Nikon files:')
-        print('\n'.join(fs))
+        print("Nikon files:")
+        print("\n".join(fs))
     else:
         # find tiffs
         fs, ops2 = get_tif_list(ops1[0])
         for ops in ops1:
-            ops['first_tiffs'] = ops2['first_tiffs']
-            ops['frames_per_folder'] = np.zeros((ops2['first_tiffs'].sum(),), np.int32)
+            ops["first_tiffs"] = ops2["first_tiffs"]
+            ops["frames_per_folder"] = np.zeros((ops2["first_tiffs"].sum(),), np.int32)
     for ops in ops1:
-        ops['filelist'] = fs
+        ops["filelist"] = fs
     return ops1, fs, reg_file, reg_file_chan2
 
 
@@ -262,61 +263,62 @@ def init_ops(ops):
     Parameters
     ----------
     ops : dictionary
-        'nplanes', 'save_path', 'save_folder', 'fast_disk', 'nchannels', 'keep_movie_raw'
-        + (if mesoscope) 'dy', 'dx', 'lines'
+        "nplanes", "save_path", "save_folder", "fast_disk", "nchannels", "keep_movie_raw"
+        + (if mesoscope) "dy", "dx", "lines"
 
     Returns
     -------
         ops1 : list of dictionaries
-            adds fields 'save_path0', 'reg_file'
-            (depending on ops: 'raw_file', 'reg_file_chan2', 'raw_file_chan2')
+            adds fields "save_path0", "reg_file"
+            (depending on ops: "raw_file", "reg_file_chan2", "raw_file_chan2")
 
     """
 
-    nplanes = ops['nplanes']
-    nchannels = ops['nchannels']
-    if 'lines' in ops:
-        lines = ops['lines']
-    if 'iplane' in ops:
-        iplane = ops['iplane']
-        #ops['nplanes'] = len(ops['lines'])
+    nplanes = ops["nplanes"]
+    nchannels = ops["nchannels"]
+    if "lines" in ops:
+        lines = ops["lines"]
+    if "iplane" in ops:
+        iplane = ops["iplane"]
+        #ops["nplanes"] = len(ops["lines"])
     ops1 = []
-    if ('fast_disk' not in ops) or len(ops['fast_disk'])==0:
-        ops['fast_disk'] = ops['save_path0']
-    fast_disk = ops['fast_disk']
+    if ("fast_disk" not in ops) or len(ops["fast_disk"]) == 0:
+        ops["fast_disk"] = ops["save_path0"]
+    fast_disk = ops["fast_disk"]
     # for mesoscope recording FOV locations
-    if 'dy' in ops and ops['dy']!='':
-        dy = ops['dy']
-        dx = ops['dx']
+    if "dy" in ops and ops["dy"] != "":
+        dy = ops["dy"]
+        dx = ops["dx"]
     # compile ops into list across planes
-    for j in range(0,nplanes):
-        if len(ops['save_folder']) > 0:
-            ops['save_path'] = os.path.join(ops['save_path0'], ops['save_folder'], 'plane%d'%j)
+    for j in range(0, nplanes):
+        if len(ops["save_folder"]) > 0:
+            ops["save_path"] = os.path.join(ops["save_path0"], ops["save_folder"],
+                                            "plane%d" % j)
         else:
-            ops['save_path'] = os.path.join(ops['save_path0'], 'suite2p', 'plane%d'%j)
-        
-        if ('fast_disk' not in ops) or len(ops['fast_disk'])==0:
-            ops['fast_disk'] = ops['save_path0'].copy()
-        fast_disk = os.path.join(ops['fast_disk'], 'suite2p', 'plane%d'%j)
-        ops['ops_path'] = os.path.join(ops['save_path'],'ops.npy')
-        ops['reg_file'] = os.path.join(fast_disk, 'data.bin')
-        if 'keep_movie_raw' in ops and ops['keep_movie_raw']:
-            ops['raw_file'] = os.path.join(fast_disk, 'data_raw.bin')
-        if 'lines' in ops:
-            ops['lines'] = lines[j]
-        if 'iplane' in ops:
-            ops['iplane'] = iplane[j]
-        if nchannels>1:
-            ops['reg_file_chan2'] = os.path.join(fast_disk, 'data_chan2.bin')
-            if 'keep_movie_raw' in ops and ops['keep_movie_raw']:
-                ops['raw_file_chan2'] = os.path.join(fast_disk, 'data_chan2_raw.bin')
-        if 'dy' in ops and ops['dy']!='':
-            ops['dy'] = dy[j]
-            ops['dx'] = dx[j]
+            ops["save_path"] = os.path.join(ops["save_path0"], "suite2p", "plane%d" % j)
+
+        if ("fast_disk" not in ops) or len(ops["fast_disk"]) == 0:
+            ops["fast_disk"] = ops["save_path0"].copy()
+        fast_disk = os.path.join(ops["fast_disk"], "suite2p", "plane%d" % j)
+        ops["ops_path"] = os.path.join(ops["save_path"], "ops.npy")
+        ops["reg_file"] = os.path.join(fast_disk, "data.bin")
+        if "keep_movie_raw" in ops and ops["keep_movie_raw"]:
+            ops["raw_file"] = os.path.join(fast_disk, "data_raw.bin")
+        if "lines" in ops:
+            ops["lines"] = lines[j]
+        if "iplane" in ops:
+            ops["iplane"] = iplane[j]
+        if nchannels > 1:
+            ops["reg_file_chan2"] = os.path.join(fast_disk, "data_chan2.bin")
+            if "keep_movie_raw" in ops and ops["keep_movie_raw"]:
+                ops["raw_file_chan2"] = os.path.join(fast_disk, "data_chan2_raw.bin")
+        if "dy" in ops and ops["dy"] != "":
+            ops["dy"] = dy[j]
+            ops["dx"] = dx[j]
         if not os.path.isdir(fast_disk):
             os.makedirs(fast_disk)
-        if not os.path.isdir(ops['save_path']):
-            os.makedirs(ops['save_path'])
+        if not os.path.isdir(ops["save_path"]):
+            os.makedirs(ops["save_path"])
         ops1.append(ops.copy())
     return ops1
 
@@ -332,7 +334,7 @@ def get_suite2p_path(path: Path) -> Path:
         for path_idx in range(len(path.parts) - 1, 0, -1):
             if path.parts[path_idx] == "suite2p":
                 new_path = Path(path.parts[0])
-                for path_part in path.parts[1 : path_idx + 1]:
+                for path_part in path.parts[1:path_idx + 1]:
                     new_path = new_path.joinpath(path_part)
                 break
     else:
diff --git a/suite2p/ops/clean.py b/suite2p/ops/clean.py
index 9fd77f89c..b1e5593ea 100644
--- a/suite2p/ops/clean.py
+++ b/suite2p/ops/clean.py
@@ -5,11 +5,12 @@
 
 def main(ops1):
     # cleaning stuff
-    print('cleaning!')
+    print("cleaning!")
 
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser(description='Suite2p parameters')
-    parser.add_argument('ops_file', type=str, help='ops file path')
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(description="Suite2p parameters")
+    parser.add_argument("ops_file", type=str, help="ops file path")
     args = parser.parse_args()
     ops1 = np.load(args.ops_file)
 
diff --git a/suite2p/registration/__init__.py b/suite2p/registration/__init__.py
index 63b132506..6be475818 100644
--- a/suite2p/registration/__init__.py
+++ b/suite2p/registration/__init__.py
@@ -1,3 +1,4 @@
-from .register import register_binary, registration_wrapper
+from .register import (registration_wrapper, save_registration_outputs_to_ops,
+                       compute_enhanced_mean_image)
 from .metrics import get_pc_metrics
 from .zalign import compute_zpos
diff --git a/suite2p/registration/bidiphase.py b/suite2p/registration/bidiphase.py
index f3c1cc4db..92b12355c 100644
--- a/suite2p/registration/bidiphase.py
+++ b/suite2p/registration/bidiphase.py
@@ -26,19 +26,19 @@ def compute(frames: np.ndarray) -> int:
 
     d2 = np.conj(fft.fft(frames[:, ::2, :], axis=2))
     d2 /= np.abs(d2) + 1e-5
-    d2 = d2[:,:d1.shape[1],:]
+    d2 = d2[:, :d1.shape[1], :]
 
     cc = np.real(fft.ifft(d1 * d2, axis=2))
     cc = cc.mean(axis=1).mean(axis=0)
     cc = fft.fftshift(cc)
 
-    bidiphase = -(np.argmax(cc[-10 + Lx // 2 : 11 + Lx // 2]) - 10)
+    bidiphase = -(np.argmax(cc[-10 + Lx // 2:11 + Lx // 2]) - 10)
     return bidiphase
 
 
 def shift(frames: np.ndarray, bidiphase: int) -> None:
     """
-    Shift last axis of 'frames' by bidirectional phase offset in-place, bidiphase.
+    Shift last axis of "frames" by bidirectional phase offset in-place, bidiphase.
 
     Parameters
     ----------
@@ -49,4 +49,4 @@ def shift(frames: np.ndarray, bidiphase: int) -> None:
     if bidiphase > 0:
         frames[:, 1::2, bidiphase:] = frames[:, 1::2, :-bidiphase]
     else:
-        frames[:, 1::2, :bidiphase] = frames[:, 1::2, -bidiphase:]
\ No newline at end of file
+        frames[:, 1::2, :bidiphase] = frames[:, 1::2, -bidiphase:]
diff --git a/suite2p/registration/metrics.py b/suite2p/registration/metrics.py
index 34d07c001..2d7bca023 100644
--- a/suite2p/registration/metrics.py
+++ b/suite2p/registration/metrics.py
@@ -15,9 +15,10 @@
 from . import rigid, nonrigid, utils, bidiphase
 from .. import io
 
+
 def pclowhigh(mov, nlowhigh, nPC, random_state):
     """
-    Compute mean of top and bottom PC weights for nPC's of mov
+    Compute mean of top and bottom PC weights for nPC"s of mov
 
     computes nPC PCs of mov and returns average of top and bottom
 
@@ -52,18 +53,19 @@ def pclowhigh(mov, nlowhigh, nPC, random_state):
     v = pca.components_.T
     w = pca.singular_values_
     mov += mimg
-    mov = np.transpose(np.reshape(mov, (-1, Ly, Lx)), (1,2,0))
-    pclow  = np.zeros((nPC, Ly, Lx), np.float32)
+    mov = np.transpose(np.reshape(mov, (-1, Ly, Lx)), (1, 2, 0))
+    pclow = np.zeros((nPC, Ly, Lx), np.float32)
     pchigh = np.zeros((nPC, Ly, Lx), np.float32)
     isort = np.argsort(v, axis=0)
     for i in range(nPC):
-        pclow[i] = mov[:,:,isort[:nlowhigh, i]].mean(axis=-1)
-        pchigh[i] = mov[:,:,isort[-nlowhigh:, i]].mean(axis=-1)
+        pclow[i] = mov[:, :, isort[:nlowhigh, i]].mean(axis=-1)
+        pchigh[i] = mov[:, :, isort[-nlowhigh:, i]].mean(axis=-1)
     return pclow, pchigh, w, v
 
 
-def pc_register(pclow, pchigh, bidi_corrected, spatial_hp=None, pre_smooth=None, smooth_sigma=1.15, smooth_sigma_time=0,
-                block_size=(128,128), maxregshift=0.1, maxregshiftNR=10, reg_1p=False, snr_thresh=1.25,
+def pc_register(pclow, pchigh, bidi_corrected, spatial_hp=None, pre_smooth=None,
+                smooth_sigma=1.15, smooth_sigma_time=0, block_size=(128, 128),
+                maxregshift=0.1, maxregshiftNR=10, reg_1p=False, snr_thresh=1.25,
                 is_nonrigid=True, bidiphase_offset=0, spatial_taper=50.0):
     """
     register top and bottom of PCs to each other
@@ -106,11 +108,10 @@ def pc_register(pclow, pchigh, bidi_corrected, spatial_hp=None, pre_smooth=None,
     # registration settings
     nPC, Ly, Lx = pclow.shape
     yblock, xblock, nblocks, block_size, NRsm = nonrigid.make_blocks(
-        Ly=Ly, Lx=Lx, block_size=np.array(block_size)
-    )
+        Ly=Ly, Lx=Lx, block_size=np.array(block_size))
     maxregshiftNR = np.array(maxregshiftNR)
 
-    X = np.zeros((nPC,3))
+    X = np.zeros((nPC, 3))
     for i in range(nPC):
         refImg = pclow[i]
         Img = pchigh[i][np.newaxis, :, :]
@@ -122,13 +123,12 @@ def pc_register(pclow, pchigh, bidi_corrected, spatial_hp=None, pre_smooth=None,
                 data = utils.spatial_smooth(data, int(pre_smooth))
             refImg = utils.spatial_high_pass(data, int(spatial_hp))
 
-        rmin, rmax = np.int16(np.percentile(refImg,1)), np.int16(np.percentile(refImg,99))
+        rmin, rmax = np.int16(np.percentile(refImg,
+                                            1)), np.int16(np.percentile(refImg, 99))
         refImg = np.clip(refImg, rmin, rmax)
 
         maskMul, maskOffset = rigid.compute_masks(
-            refImg=refImg,
-            maskSlope=spatial_taper if reg_1p else 3 * smooth_sigma
-        )
+            refImg=refImg, maskSlope=spatial_taper if reg_1p else 3 * smooth_sigma)
         cfRefImg = rigid.phasecorr_reference(
             refImg=refImg,
             smooth_sigma=smooth_sigma,
@@ -146,8 +146,6 @@ def pc_register(pclow, pchigh, bidi_corrected, spatial_hp=None, pre_smooth=None,
                 xblock=xblock,
             )
 
-
-
         if bidiphase_offset and not bidi_corrected:
             bidiphase.shift(Img, bidiphase_offset)
 
@@ -188,9 +186,9 @@ def pc_register(pclow, pchigh, bidi_corrected, spatial_hp=None, pre_smooth=None,
                 maxregshiftNR=maxregshiftNR,
             )
 
-            X[i,1] = np.mean((ymax1**2 + xmax1**2)**.5)
-            X[i,0] = np.mean((ymax[0]**2 + xmax[0]**2)**.5)
-            X[i,2] = np.amax((ymax1**2 + xmax1**2)**.5)
+            X[i, 1] = np.mean((ymax1**2 + xmax1**2)**.5)
+            X[i, 0] = np.mean((ymax[0]**2 + xmax[0]**2)**.5)
+            X[i, 2] = np.amax((ymax1**2 + xmax1**2)**.5)
     return X
 
 
@@ -198,158 +196,160 @@ def get_pc_metrics(mov, ops, use_red=False):
     """
     Computes registration metrics using top PCs of registered movie
 
-    movie saved as binary file ops['reg_file']
-    metrics saved to ops['regPC'] and ops['X']
-    'regDX' is nPC x 3 where X[:,0] is rigid, X[:,1] is average nonrigid, X[:,2] is max nonrigid shifts
-    'regPC' is average of top and bottom frames for each PC
-    'tPC' is PC across time frames
+    movie saved as binary file ops["reg_file"]
+    metrics saved to ops["regPC"] and ops["X"]
+    "regDX" is nPC x 3 where X[:,0] is rigid, X[:,1] is average nonrigid, X[:,2] is max nonrigid shifts
+    "regPC" is average of top and bottom frames for each PC
+    "tPC" is PC across time frames
 
     Parameters
     ----------
     ops : dict
-        'nframes', 'Ly', 'Lx', 'reg_file' (if use_red=True, 'reg_file_chan2')
-        (optional, 'refImg', 'block_size', 'maxregshiftNR', 'smooth_sigma', 'maxregshift', '1Preg')
+        "nframes", "Ly", "Lx", "reg_file" (if use_red=True, "reg_file_chan2")
+        (optional, "refImg", "block_size", "maxregshiftNR", "smooth_sigma", "maxregshift", "1Preg")
     use_red : :obj:`bool`, optional
-        default False, whether to use 'reg_file' or 'reg_file_chan2'
+        default False, whether to use "reg_file" or "reg_file_chan2"
 
     Returns
     -------
     ops : dict
-        The same as the ops input, but will now include 'regPC', 'tPC', and 'regDX'.
+        The same as the ops input, but will now include "regPC", "tPC", and "regDX".
 
     """
-    random_state = ops['reg_metrics_rs'] if 'reg_metrics_rs' in ops else None
-    nPC = ops['reg_metric_n_pc'] if 'reg_metric_n_pc' in ops else 30
-    pclow, pchigh, sv, ops['tPC'] = pclowhigh(mov, nlowhigh=np.minimum(300, int(ops['nframes'] / 2)),
-                                              nPC=nPC, random_state=random_state
-                                    )
-    ops['regPC'] = np.concatenate((pclow[np.newaxis, :, :, :], pchigh[np.newaxis, :, :, :]), axis=0)
-
-    ops['regDX'] = pc_register(
-        pclow,
-        pchigh,
-        spatial_hp=ops['spatial_hp_reg'],
-        pre_smooth=ops['pre_smooth'],
-        bidi_corrected=ops['bidi_corrected'],
-        smooth_sigma=ops['smooth_sigma'] if 'smooth_sigma' in ops else 1.15,
-        smooth_sigma_time=ops['smooth_sigma_time'],
-        block_size=ops['block_size'] if 'block_size' in ops else [128, 128],
-        maxregshift=ops['maxregshift'] if 'maxregshift' in ops else 0.1,
-        maxregshiftNR=ops['maxregshiftNR'] if 'maxregshiftNR' in ops else 5,
-        reg_1p=ops['1Preg'] if '1Preg' in ops else False,
-        snr_thresh=ops['snr_thresh'],
-        is_nonrigid=ops['nonrigid'],
-        bidiphase_offset=ops['bidiphase'],
-        spatial_taper=ops['spatial_taper']
-    )
+    random_state = ops["reg_metrics_rs"] if "reg_metrics_rs" in ops else None
+    nPC = ops["reg_metric_n_pc"] if "reg_metric_n_pc" in ops else 30
+    pclow, pchigh, sv, ops["tPC"] = pclowhigh(
+        mov, nlowhigh=np.minimum(300, int(ops["nframes"] / 2)), nPC=nPC,
+        random_state=random_state)
+    ops["regPC"] = np.concatenate(
+        (pclow[np.newaxis, :, :, :], pchigh[np.newaxis, :, :, :]), axis=0)
+
+    ops["regDX"] = pc_register(
+        pclow, pchigh, spatial_hp=ops["spatial_hp_reg"], pre_smooth=ops["pre_smooth"],
+        bidi_corrected=ops["bidi_corrected"],
+        smooth_sigma=ops["smooth_sigma"] if "smooth_sigma" in ops else 1.15,
+        smooth_sigma_time=ops["smooth_sigma_time"],
+        block_size=ops["block_size"] if "block_size" in ops else [128, 128],
+        maxregshift=ops["maxregshift"] if "maxregshift" in ops else 0.1,
+        maxregshiftNR=ops["maxregshiftNR"] if "maxregshiftNR" in ops else 5,
+        reg_1p=ops["1Preg"] if "1Preg" in ops else False, snr_thresh=ops["snr_thresh"],
+        is_nonrigid=ops["nonrigid"], bidiphase_offset=ops["bidiphase"],
+        spatial_taper=ops["spatial_taper"])
     return ops
 
 
 def filt_worker(inputs):
     X, filt = inputs
     for n in range(X.shape[0]):
-        X[n,:,:] = convolve2d(X[n,:,:], filt, 'same')
+        X[n, :, :] = convolve2d(X[n, :, :], filt, "same")
     return X
 
+
 def filt_parallel(data, filt, num_cores):
     nimg = data.shape[0]
-    nbatch = int(np.ceil(nimg/float(num_cores)))
+    nbatch = int(np.ceil(nimg / float(num_cores)))
     inputs = np.arange(0, nimg, nbatch)
     irange = []
     dsplit = []
     for i in inputs:
-        ilist = i + np.arange(0,np.minimum(nbatch, nimg-i),1,int)
+        ilist = i + np.arange(0, np.minimum(nbatch, nimg - i), 1, int)
         irange.append(ilist)
-        dsplit.append([data[ilist,:, :], filt])
+        dsplit.append([data[ilist, :, :], filt])
     if num_cores > 1:
         with Pool(num_cores) as p:
             results = p.map(filt_worker, dsplit)
-        results = np.concatenate(results, axis=0 )
+        results = np.concatenate(results, axis=0)
     else:
         results = filt_worker(dsplit[0])
     return results
 
+
 def local_corr(mov, batch_size, num_cores):
     """ computes correlation image on mov (nframes x pixels x pixels) """
     nframes, Ly, Lx = mov.shape
 
-    filt = np.ones((3,3),np.float32)
-    filt[1,1] = 0
+    filt = np.ones((3, 3), np.float32)
+    filt[1, 1] = 0
     filt /= norm(filt)
-    ix=0
-    k=0
-    filtnorm = convolve2d(np.ones((Ly,Lx)),filt,'same')
+    ix = 0
+    k = 0
+    filtnorm = convolve2d(np.ones((Ly, Lx)), filt, "same")
 
-    img_corr = np.zeros((Ly,Lx), np.float32)
+    img_corr = np.zeros((Ly, Lx), np.float32)
     while ix < nframes:
-        ifr = np.arange(ix, min(ix+batch_size, nframes), 1, int)
+        ifr = np.arange(ix, min(ix + batch_size, nframes), 1, int)
 
-        X = mov[ifr,:,:]
+        X = mov[ifr, :, :]
         X = X.astype(np.float32)
         X -= X.mean(axis=0)
         Xstd = X.std(axis=0)
-        Xstd[Xstd==0] = np.inf
+        Xstd[Xstd == 0] = np.inf
         #X /= np.maximum(1, X.std(axis=0))
         X /= Xstd
         #for n in range(X.shape[0]):
-        #    X[n,:,:] *= convolve2d(X[n,:,:], filt, 'same')
+        #    X[n,:,:] *= convolve2d(X[n,:,:], filt, "same")
         X *= filt_parallel(X, filt, num_cores)
         img_corr += X.mean(axis=0)
         ix += batch_size
-        k+=1
+        k += 1
     img_corr /= filtnorm
     img_corr /= float(k)
     return img_corr
 
+
 def bin_median(mov, window=10):
-    nframes,Ly,Lx = mov.shape
+    nframes, Ly, Lx = mov.shape
     if nframes < window:
         window = nframes
-    mov = np.nanmedian(np.reshape(mov[:int(np.floor(nframes/window)*window),:,:],
-                                  (-1,window,Ly,Lx)).mean(axis=1), axis=0)
+    mov = np.nanmedian(
+        np.reshape(mov[:int(np.floor(nframes / window) * window), :, :],
+                   (-1, window, Ly, Lx)).mean(axis=1), axis=0)
     return mov
 
+
 def corr_to_template(mov, tmpl):
     nframes, Ly, Lx = mov.shape
     tmpl_flat = tmpl.flatten()
     tmpl_flat -= tmpl_flat.mean()
     tmpl_std = tmpl_flat.std()
 
-    mov_flat = np.reshape(mov,(nframes,-1)).astype(np.float32)
-    mov_flat -= mov_flat.mean(axis=1)[:,np.newaxis]
-    mov_std = (mov_flat**2).mean(axis=1) ** 0.5
+    mov_flat = np.reshape(mov, (nframes, -1)).astype(np.float32)
+    mov_flat -= mov_flat.mean(axis=1)[:, np.newaxis]
+    mov_std = (mov_flat**2).mean(axis=1)**0.5
 
     correlations = (mov_flat * tmpl_flat).mean(axis=1) / (tmpl_std * mov_std)
 
     return correlations
 
+
 def optic_flow(mov, tmpl, nflows):
     """ optic flow computation using farneback """
-    window = int(1 / 0.2) # window size
+    window = int(1 / 0.2)  # window size
     nframes, Ly, Lx = mov.shape
     mov = mov.astype(np.float32)
-    mov = np.reshape(mov[:int(np.floor(nframes/window)*window),:,:],
-                                  (-1,window,Ly,Lx)).mean(axis=1)
+    mov = np.reshape(mov[:int(np.floor(nframes / window) * window), :, :],
+                     (-1, window, Ly, Lx)).mean(axis=1)
 
-    mov = mov[np.random.permutation(mov.shape[0])[:min(nflows,mov.shape[0])], :, :]
+    mov = mov[np.random.permutation(mov.shape[0])[:min(nflows, mov.shape[0])], :, :]
 
-    pyr_scale=.5
-    levels=3
-    winsize=100
-    iterations=15
-    poly_n=5
-    poly_sigma=1.2 / 5
-    flags=0
+    pyr_scale = .5
+    levels = 3
+    winsize = 100
+    iterations = 15
+    poly_n = 5
+    poly_sigma = 1.2 / 5
+    flags = 0
 
     nframes, Ly, Lx = mov.shape
     norms = np.zeros((nframes,))
-    flows = np.zeros((nframes,Ly,Lx,2))
+    flows = np.zeros((nframes, Ly, Lx, 2))
 
     for n in range(nframes):
-        flow = cv2.calcOpticalFlowFarneback(
-            tmpl, mov[n,:,:], None, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags)
+        flow = cv2.calcOpticalFlowFarneback(tmpl, mov[n, :, :], None, pyr_scale, levels,
+                                            winsize, iterations, poly_n, poly_sigma,
+                                            flags)
 
-        flows[n,:,:,:] = flow
+        flows[n, :, :, :] = flow
         norms[n] = norm(flow)
 
     return flows, norms
@@ -358,46 +358,46 @@ def optic_flow(mov, tmpl, nflows):
 def get_flow_metrics(ops):
     """ get farneback optical flow and some other stats from normcorre paper """
     # done in batches for memory reasons
-    Ly = ops['Ly']
-    Lx = ops['Lx']
-    reg_file = open(ops['reg_file'], 'rb')
-    nbatch = ops['batch_size']
+    Ly = ops["Ly"]
+    Lx = ops["Lx"]
+    reg_file = open(ops["reg_file"], "rb")
+    nbatch = ops["batch_size"]
     nbytesread = 2 * Ly * Lx * nbatch
 
-    Lyc = ops['yrange'][1] - ops['yrange'][0]
-    Lxc = ops['xrange'][1] - ops['xrange'][0]
-    img_corr = np.zeros((Lyc,Lxc), np.float32)
-    img_median = np.zeros((Lyc,Lxc), np.float32)
+    Lyc = ops["yrange"][1] - ops["yrange"][0]
+    Lxc = ops["xrange"][1] - ops["xrange"][0]
+    img_corr = np.zeros((Lyc, Lxc), np.float32)
+    img_median = np.zeros((Lyc, Lxc), np.float32)
     correlations = np.zeros((0,), np.float32)
-    flows = np.zeros((0,Lyc,Lxc,2), np.float32)
+    flows = np.zeros((0, Lyc, Lxc, 2), np.float32)
     norms = np.zeros((0,), np.float32)
     smoothness = 0
     smoothness_corr = 0
 
-    nflows = np.minimum(ops['nframes'], int(np.floor(100 / (ops['nframes']/nbatch))))
-    ncorrs = np.minimum(ops['nframes'], int(np.floor(1000 / (ops['nframes']/nbatch))))
+    nflows = np.minimum(ops["nframes"], int(np.floor(100 / (ops["nframes"] / nbatch))))
+    ncorrs = np.minimum(ops["nframes"], int(np.floor(1000 / (ops["nframes"] / nbatch))))
 
-    k=0
+    k = 0
     while True:
         buff = reg_file.read(nbytesread)
         mov = np.frombuffer(buff, dtype=np.int16, offset=0)
         buff = []
-        if mov.size==0:
+        if mov.size == 0:
             break
         mov = np.reshape(mov, (-1, Ly, Lx))
 
-        mov = mov[np.ix_(np.arange(0, mov.shape[0],1,int),
-                  np.arange(ops['yrange'][0],ops['yrange'][1],1,int),
-                  np.arange(ops['xrange'][0],ops['xrange'][1],1,int))]
+        mov = mov[np.ix_(np.arange(0, mov.shape[0], 1, int),
+                         np.arange(ops["yrange"][0], ops["yrange"][1], 1, int),
+                         np.arange(ops["xrange"][0], ops["xrange"][1], 1, int))]
 
-        img_corr += local_corr(mov[:,:,:], 1000, ops['num_workers'])
+        img_corr += local_corr(mov[:, :, :], 1000, ops["num_workers"])
         img_median += bin_median(mov)
-        k+=1
+        k += 1
 
         smoothness += np.sqrt(
-               np.sum(np.sum(np.array(np.gradient(np.mean(mov, 0)))**2, 0)))
-        smoothness_corr += np.sqrt(
-            np.sum(np.sum(np.array(np.gradient(img_corr))**2, 0)))
+            np.sum(np.sum(np.array(np.gradient(np.mean(mov, 0)))**2, 0)))
+        smoothness_corr += np.sqrt(np.sum(np.sum(np.array(np.gradient(img_corr))**2,
+                                                 0)))
 
         tmpl = img_median / k
 
@@ -406,13 +406,12 @@ def get_flow_metrics(ops):
         if HAS_CV2:
             flows0, norms0 = optic_flow(mov, tmpl, nflows)
         else:
-            flows0=[]
-            norms0=[]
-            print('flows not computed, cv2 not installed / did not import correctly')
-
-        flows = np.vstack((flows,flows0))
-        norms = np.hstack((norms,norms0))
+            flows0 = []
+            norms0 = []
+            print("flows not computed, cv2 not installed / did not import correctly")
 
+        flows = np.vstack((flows, flows0))
+        norms = np.hstack((norms, norms0))
 
     img_corr /= float(k)
     img_median /= float(k)
diff --git a/suite2p/registration/nonrigid.py b/suite2p/registration/nonrigid.py
index 7848d64dd..a2fa2b6c8 100644
--- a/suite2p/registration/nonrigid.py
+++ b/suite2p/registration/nonrigid.py
@@ -23,7 +23,8 @@ def calculate_nblocks(L: int, block_size: int = 128) -> Tuple[int, int]:
     block_size: int
     nblocks: int
     """
-    return (L, 1) if block_size >= L else (block_size, int(np.ceil(1.5 * L / block_size)))
+    return (L, 1) if block_size >= L else (block_size,
+                                           int(np.ceil(1.5 * L / block_size)))
 
 
 def make_blocks(Ly, Lx, block_size=(128, 128)):
@@ -53,19 +54,28 @@ def make_blocks(Ly, Lx, block_size=(128, 128)):
     block_size = (block_size_y, block_size_x)
 
     # todo: could rounding to int here over-represent some pixels over others?
-    ystart = np.linspace(0, Ly - block_size[0], ny).astype('int')
-    xstart = np.linspace(0, Lx - block_size[1], nx).astype('int')
-    yblock = [np.array([ystart[iy], ystart[iy] + block_size[0]]) for iy in range(ny) for _ in range(nx)]
-    xblock = [np.array([xstart[ix], xstart[ix] + block_size[1]]) for _ in range(ny) for ix in range(nx)]
+    ystart = np.linspace(0, Ly - block_size[0], ny).astype("int")
+    xstart = np.linspace(0, Lx - block_size[1], nx).astype("int")
+    yblock = [
+        np.array([ystart[iy], ystart[iy] + block_size[0]])
+        for iy in range(ny)
+        for _ in range(nx)
+    ]
+    xblock = [
+        np.array([xstart[ix], xstart[ix] + block_size[1]])
+        for _ in range(ny)
+        for ix in range(nx)
+    ]
 
     NRsm = kernelD2(xs=np.arange(nx), ys=np.arange(ny)).T
 
     return yblock, xblock, [ny, nx], block_size, NRsm
 
 
-def phasecorr_reference(refImg0: np.ndarray, maskSlope, smooth_sigma, yblock: np.ndarray, xblock: np.ndarray):
+def phasecorr_reference(refImg0: np.ndarray, maskSlope, smooth_sigma,
+                        yblock: np.ndarray, xblock: np.ndarray):
     """
-    Computes taper and fft'ed reference image for phasecorr.
+    Computes taper and fft"ed reference image for phasecorr.
 
     Parameters
     ----------
@@ -86,14 +96,17 @@ def phasecorr_reference(refImg0: np.ndarray, maskSlope, smooth_sigma, yblock: np
     dims = (nb, Ly, Lx)
     cfRef_dims = dims
     gaussian_filter = gaussian_fft(smooth_sigma, *cfRef_dims[1:])
-    cfRefImg1 = np.zeros(cfRef_dims, 'complex64')
+    cfRefImg1 = np.zeros(cfRef_dims, "complex64")
 
     maskMul = spatial_taper(maskSlope, *refImg0.shape)
-    maskMul1 = np.zeros(dims, 'float32')
+    maskMul1 = np.zeros(dims, "float32")
     maskMul1[:] = spatial_taper(2 * smooth_sigma, Ly, Lx)
-    maskOffset1 = np.zeros(dims, 'float32')
-    for yind, xind, maskMul1_n, maskOffset1_n, cfRefImg1_n in zip(yblock, xblock, maskMul1, maskOffset1, cfRefImg1):
-        ix = np.ix_(np.arange(yind[0], yind[-1]).astype('int'), np.arange(xind[0], xind[-1]).astype('int'))
+    maskOffset1 = np.zeros(dims, "float32")
+    for yind, xind, maskMul1_n, maskOffset1_n, cfRefImg1_n in zip(
+            yblock, xblock, maskMul1, maskOffset1, cfRefImg1):
+        ix = np.ix_(
+            np.arange(yind[0], yind[-1]).astype("int"),
+            np.arange(xind[0], xind[-1]).astype("int"))
         refImg = refImg0[ix]
 
         # mask params
@@ -105,7 +118,10 @@ def phasecorr_reference(refImg0: np.ndarray, maskSlope, smooth_sigma, yblock: np
         cfRefImg1_n /= 1e-5 + np.absolute(cfRefImg1_n)
         cfRefImg1_n[:] *= gaussian_filter
 
-    return maskMul1[:, np.newaxis, :, :], maskOffset1[:, np.newaxis, :, :], cfRefImg1[:, np.newaxis, :, :]
+    return maskMul1[:, np.
+                    newaxis, :, :], maskOffset1[:, np.
+                                                newaxis, :, :], cfRefImg1[:, np.
+                                                                          newaxis, :, :]
 
 
 def getSNR(cc: np.ndarray, lcorr: int, lpad: int) -> float:
@@ -127,14 +143,19 @@ def getSNR(cc: np.ndarray, lcorr: int, lpad: int) -> float:
     cc0 = cc[:, lpad:-lpad, lpad:-lpad].reshape(cc.shape[0], -1)
     # set to 0 all pts +-lpad from ymax,xmax
     cc1 = cc.copy()
-    for c1, ymax, xmax in zip(cc1, *np.unravel_index(np.argmax(cc0, axis=1), (2 * lcorr + 1, 2 * lcorr + 1))):
+    for c1, ymax, xmax in zip(
+            cc1,
+            *np.unravel_index(np.argmax(cc0, axis=1), (2 * lcorr + 1, 2 * lcorr + 1))):
         c1[ymax:ymax + 2 * lpad, xmax:xmax + 2 * lpad] = 0
 
-    snr = np.amax(cc0, axis=1) / np.maximum(1e-10, np.amax(cc1.reshape(cc.shape[0], -1), axis=1))  # ensure positivity for outlier cases
+    snr = np.amax(cc0, axis=1) / np.maximum(
+        1e-10, np.amax(cc1.reshape(cc.shape[0], -1),
+                       axis=1))  # ensure positivity for outlier cases
     return snr
 
 
-def phasecorr(data: np.ndarray, maskMul, maskOffset, cfRefImg, snr_thresh, NRsm, xblock, yblock, maxregshiftNR, subpixel: int = 10, lpad: int = 3):
+def phasecorr(data: np.ndarray, maskMul, maskOffset, cfRefImg, snr_thresh, NRsm, xblock,
+              yblock, maxregshiftNR, subpixel: int = 10, lpad: int = 3):
     """
     Compute phase correlations for each block
     
@@ -163,43 +184,45 @@ def phasecorr(data: np.ndarray, maskMul, maskOffset, cfRefImg, snr_thresh, NRsm,
     xmax1
     cmax1
     """
-    
+
     Kmat, nup = mat_upsample(lpad=3)
 
     nimg = data.shape[0]
     ly, lx = cfRefImg.shape[-2:]
 
     # maximum registration shift allowed
-    lcorr = int(np.minimum(np.round(maxregshiftNR), np.floor(np.minimum(ly, lx) / 2.) - lpad))
+    lcorr = int(
+        np.minimum(np.round(maxregshiftNR),
+                   np.floor(np.minimum(ly, lx) / 2.) - lpad))
     nb = len(yblock)
 
     # shifts and corrmax
-    Y = np.zeros((nimg, nb, ly, lx), 'float32')
+    Y = np.zeros((nimg, nb, ly, lx), "float32")
     for n in range(nb):
         yind, xind = yblock[n], xblock[n]
-        Y[:,n] = data[:, yind[0]:yind[-1], xind[0]:xind[-1]]
+        Y[:, n] = data[:, yind[0]:yind[-1], xind[0]:xind[-1]]
     Y = addmultiply(Y, maskMul, maskOffset)
-    batch = min(64, Y.shape[1]) #16
+    batch = min(64, Y.shape[1])  #16
     for n in np.arange(0, nb, batch):
-        nend = min(Y.shape[1], n+batch)
-        Y[:,n:nend] = convolve(mov=Y[:,n:nend], img=cfRefImg[n:nend])
+        nend = min(Y.shape[1], n + batch)
+        Y[:, n:nend] = convolve(mov=Y[:, n:nend], img=cfRefImg[n:nend])
 
     # calculate ccsm
     lhalf = lcorr + lpad
     cc0 = np.real(
-        np.block(
-            [[Y[:, :, -lhalf:,    -lhalf:], Y[:, :, -lhalf:,    :lhalf + 1]],
-             [Y[:, :, :lhalf + 1, -lhalf:], Y[:, :, :lhalf + 1, :lhalf + 1]]]
-        )
-    )
+        np.block([[Y[:, :, -lhalf:, -lhalf:], Y[:, :, -lhalf:, :lhalf + 1]],
+                  [Y[:, :, :lhalf + 1, -lhalf:], Y[:, :, :lhalf + 1, :lhalf + 1]]]))
     cc0 = cc0.transpose(1, 0, 2, 3)
     cc0 = cc0.reshape(cc0.shape[0], -1)
 
     cc2 = [cc0, NRsm @ cc0, NRsm @ NRsm @ cc0]
-    cc2 = [c2.reshape(nb, nimg, 2 * lcorr + 2 * lpad + 1, 2 * lcorr + 2 * lpad + 1) for c2 in cc2]
+    cc2 = [
+        c2.reshape(nb, nimg, 2 * lcorr + 2 * lpad + 1, 2 * lcorr + 2 * lpad + 1)
+        for c2 in cc2
+    ]
     ccsm = cc2[0]
     for n in range(nb):
-        snr = np.ones(nimg, 'float32')
+        snr = np.ones(nimg, "float32")
         for j, c2 in enumerate(cc2):
             ism = snr < snr_thresh
             if np.sum(ism) == 0:
@@ -216,13 +239,13 @@ def phasecorr(data: np.ndarray, maskMul, maskOffset, cfRefImg, snr_thresh, NRsm,
     xmax1 = np.empty((nimg, nb), np.float32)
     ymax = np.empty((nb,), np.int32)
     xmax = np.empty((nb,), np.int32)
-    
+
     for t in range(nimg):
-        ccmat = np.empty((nb, 2*lpad+1, 2*lpad+1), np.float32)
+        ccmat = np.empty((nb, 2 * lpad + 1, 2 * lpad + 1), np.float32)
         for n in range(nb):
             ix = np.argmax(ccsm[n, t][lpad:-lpad, lpad:-lpad], axis=None)
             ym, xm = np.unravel_index(ix, (2 * lcorr + 1, 2 * lcorr + 1))
-            ccmat[n] = ccsm[n, t][ ym:ym + 2 * lpad + 1, xm:xm + 2 * lpad + 1]
+            ccmat[n] = ccsm[n, t][ym:ym + 2 * lpad + 1, xm:xm + 2 * lpad + 1]
             ymax[n], xmax[n] = ym - lcorr, xm - lcorr
         ccb = ccmat.reshape(nb, -1) @ Kmat
         cmax1[t] = np.amax(ccb, axis=1)
@@ -233,11 +256,13 @@ def phasecorr(data: np.ndarray, maskMul, maskOffset, cfRefImg, snr_thresh, NRsm,
     return ymax1, xmax1, cmax1
 
 
-@njit(['(int16[:, :],float32[:,:], float32[:,:], float32[:,:])', 
-        '(float32[:, :],float32[:,:], float32[:,:], float32[:,:])'], cache=True)
+@njit([
+    "(int16[:, :],float32[:,:], float32[:,:], float32[:,:])",
+    "(float32[:, :],float32[:,:], float32[:,:], float32[:,:])"
+], cache=True)
 def map_coordinates(I, yc, xc, Y) -> None:
     """
-    In-place bilinear transform of image 'I' with ycoordinates yc and xcoordinates xc to Y
+    In-place bilinear transform of image "I" with ycoordinates yc and xcoordinates xc to Y
     
     Parameters
     -------------
@@ -249,27 +274,29 @@ def map_coordinates(I, yc, xc, Y) -> None:
     Y : Ly x Lx
         shifted I
     """
-    Ly,Lx = I.shape
+    Ly, Lx = I.shape
     yc_floor = yc.astype(np.int32)
     xc_floor = xc.astype(np.int32)
     yc = yc - yc_floor
     xc = xc - xc_floor
     for i in range(yc_floor.shape[0]):
         for j in range(yc_floor.shape[1]):
-            yf = min(Ly-1, max(0, yc_floor[i,j]))
-            xf = min(Lx-1, max(0, xc_floor[i,j]))
-            yf1= min(Ly-1, yf+1)
-            xf1= min(Lx-1, xf+1)
-            y = yc[i,j]
-            x = xc[i,j]
-            Y[i,j] = (np.float32(I[yf, xf]) * (1 - y) * (1 - x) +
-                      np.float32(I[yf, xf1]) * (1 - y) * x +
-                      np.float32(I[yf1, xf]) * y * (1 - x) +
-                      np.float32(I[yf1, xf1]) * y * x )
-
-
-@njit(['int16[:, :,:], float32[:,:,:], float32[:,:,:], float32[:,:], float32[:,:], float32[:,:,:]',
-       'float32[:, :,:], float32[:,:,:], float32[:,:,:], float32[:,:], float32[:,:], float32[:,:,:]'], parallel=True, cache=True)
+            yf = min(Ly - 1, max(0, yc_floor[i, j]))
+            xf = min(Lx - 1, max(0, xc_floor[i, j]))
+            yf1 = min(Ly - 1, yf + 1)
+            xf1 = min(Lx - 1, xf + 1)
+            y = yc[i, j]
+            x = xc[i, j]
+            Y[i,
+              j] = (np.float32(I[yf, xf]) * (1 - y) * (1 - x) + np.float32(I[yf, xf1]) *
+                    (1 - y) * x + np.float32(I[yf1, xf]) * y * (1 - x) +
+                    np.float32(I[yf1, xf1]) * y * x)
+
+
+@njit([
+    "int16[:, :,:], float32[:,:,:], float32[:,:,:], float32[:,:], float32[:,:], float32[:,:,:]",
+    "float32[:, :,:], float32[:,:,:], float32[:,:,:], float32[:,:], float32[:,:], float32[:,:,:]"
+], parallel=True, cache=True)
 def shift_coordinates(data, yup, xup, mshy, mshx, Y):
     """
     Shift data into yup and xup coordinates
@@ -289,10 +316,11 @@ def shift_coordinates(data, yup, xup, mshy, mshx, Y):
         shifted data
     """
     for t in prange(data.shape[0]):
-        map_coordinates(data[t], mshy+yup[t], mshx+xup[t], Y[t])
+        map_coordinates(data[t], mshy + yup[t], mshx + xup[t], Y[t])
 
 
-@njit((float32[:, :,:], float32[:,:,:], float32[:,:], float32[:,:], float32[:,:,:], float32[:,:,:]), parallel=True, cache=True)
+@njit((float32[:, :, :], float32[:, :, :], float32[:, :], float32[:, :],
+       float32[:, :, :], float32[:, :, :]), parallel=True, cache=True)
 def block_interp(ymax1, xmax1, mshy, mshx, yup, xup):
     """
     interpolate from ymax1 to mshy to create coordinate transforms
@@ -311,8 +339,10 @@ def block_interp(ymax1, xmax1, mshy, mshx, yup, xup):
         x shifts for each coordinate
     """
     for t in prange(ymax1.shape[0]):
-        map_coordinates(ymax1[t], mshy, mshx, yup[t])  # y shifts for blocks to coordinate map
-        map_coordinates(xmax1[t], mshy, mshx, xup[t])  # x shifts for blocks to coordinate map
+        map_coordinates(ymax1[t], mshy, mshx,
+                        yup[t])  # y shifts for blocks to coordinate map
+        map_coordinates(xmax1[t], mshy, mshx,
+                        xup[t])  # x shifts for blocks to coordinate map
 
 
 def upsample_block_shifts(Lx, Ly, nblocks, xblock, yblock, ymax1, xmax1):
@@ -348,7 +378,8 @@ def upsample_block_shifts(Lx, Ly, nblocks, xblock, yblock, ymax1, xmax1):
     # includes centers of blocks AND edges of blocks
     # note indices are flipped for control points
     # block centers
-    yb = np.array(yblock[::nblocks[1]]).mean(axis=1)  # this recovers the coordinates of the meshgrid from (yblock, xblock)
+    yb = np.array(yblock[::nblocks[1]]).mean(
+        axis=1)  # this recovers the coordinates of the meshgrid from (yblock, xblock)
     xb = np.array(xblock[:nblocks[1]]).mean(axis=1)
 
     iy = np.interp(np.arange(Ly), yb, np.arange(yb.size)).astype(np.float32)
@@ -405,8 +436,8 @@ def transform_data(data, nblocks, xblock, yblock, ymax1, xmax1, bilinear=True):
         xup = np.round(xup)
 
     # use shifts and do bilinear interpolation
-    mshx, mshy = np.meshgrid(np.arange(Lx, dtype=np.float32), np.arange(Ly, dtype=np.float32))
+    mshx, mshy = np.meshgrid(np.arange(Lx, dtype=np.float32),
+                             np.arange(Ly, dtype=np.float32))
     Y = np.zeros_like(data, dtype=np.float32)
     shift_coordinates(data, yup, xup, mshy, mshx, Y)
     return Y
-
diff --git a/suite2p/registration/register.py b/suite2p/registration/register.py
index a99a4fce1..c64703ff8 100644
--- a/suite2p/registration/register.py
+++ b/suite2p/registration/register.py
@@ -10,7 +10,9 @@
 from . import bidiphase as bidi
 from . import utils, rigid, nonrigid
 
-def compute_crop(xoff: int, yoff: int, corrXY, th_badframes, badframes, maxregshift, Ly: int, Lx:int):
+
+def compute_crop(xoff: int, yoff: int, corrXY, th_badframes, badframes, maxregshift,
+                 Ly: int, Lx: int):
     """ determines how much to crop FOV based on motion
     
     determines badframes which are frames with large outlier shifts
@@ -37,7 +39,7 @@ def compute_crop(xoff: int, yoff: int, corrXY, th_badframes, badframes, maxregsh
     yrange
     xrange
     """
-    filter_window = min((len(yoff)//2)*2 - 1, 101)
+    filter_window = min((len(yoff) // 2) * 2 - 1, 101)
     dx = xoff - medfilt(xoff, filter_window)
     dy = yoff - medfilt(yoff, filter_window)
     # offset in x and y (normed by mean offset)
@@ -54,7 +56,9 @@ def compute_crop(xoff: int, yoff: int, corrXY, th_badframes, badframes, maxregsh
         ymin = np.ceil(np.abs(yoff[np.logical_not(badframes)]).max())
         xmin = np.ceil(np.abs(xoff[np.logical_not(badframes)]).max())
     else:
-        warn('WARNING: >50% of frames have large movements, registration likely problematic')
+        warn(
+            "WARNING: >50% of frames have large movements, registration likely problematic"
+        )
         ymin = np.ceil(np.abs(yoff).max())
         xmin = np.ceil(np.abs(xoff).max())
     ymax = Ly - ymin
@@ -83,18 +87,18 @@ def pick_initial_reference(frames: np.ndarray):
         size [Ly x Lx], initial reference image
 
     """
-    nimg,Ly,Lx = frames.shape
-    frames = np.reshape(frames, (nimg,-1)).astype('float32')
+    nimg, Ly, Lx = frames.shape
+    frames = np.reshape(frames, (nimg, -1)).astype("float32")
     frames = frames - np.reshape(frames.mean(axis=1), (nimg, 1))
     cc = np.matmul(frames, frames.T)
     ndiag = np.sqrt(np.diag(cc))
     cc = cc / np.outer(ndiag, ndiag)
-    CCsort = -np.sort(-cc, axis = 1)
-    bestCC = np.mean(CCsort[:, 1:20], axis=1);
+    CCsort = -np.sort(-cc, axis=1)
+    bestCC = np.mean(CCsort[:, 1:20], axis=1)
     imax = np.argmax(bestCC)
     indsort = np.argsort(-cc[imax, :])
-    refImg = np.mean(frames[indsort[0:20], :], axis = 0)
-    refImg = np.reshape(refImg, (Ly,Lx))
+    refImg = np.mean(frames[indsort[0:20], :], axis=0)
+    refImg = np.reshape(refImg, (Ly, Lx))
     return refImg
 
 
@@ -118,14 +122,14 @@ def compute_reference(frames, ops=default_ops()):
         size [Ly x Lx], initial reference image
 
     """
-    
+
     refImg = pick_initial_reference(frames)
-    if ops['1Preg']:
-        if ops['pre_smooth']:
-            refImg = utils.spatial_smooth(refImg, int(ops['pre_smooth']))
-            frames = utils.spatial_smooth(frames, int(ops['pre_smooth']))
-        refImg = utils.spatial_high_pass(refImg, int(ops['spatial_hp_reg']))
-        frames = utils.spatial_high_pass(frames, int(ops['spatial_hp_reg']))
+    if ops["1Preg"]:
+        if ops["pre_smooth"]:
+            refImg = utils.spatial_smooth(refImg, int(ops["pre_smooth"]))
+            frames = utils.spatial_smooth(frames, int(ops["pre_smooth"]))
+        refImg = utils.spatial_high_pass(refImg, int(ops["spatial_hp_reg"]))
+        frames = utils.spatial_high_pass(frames, int(ops["spatial_hp_reg"]))
 
     niter = 8
     for iter in range(0, niter):
@@ -135,15 +139,15 @@ def compute_reference(frames, ops=default_ops()):
                 frames,
                 *rigid.compute_masks(
                     refImg=refImg,
-                    maskSlope=ops['spatial_taper'] if ops['1Preg'] else 3 * ops['smooth_sigma'],
-                )
-            ),
+                    maskSlope=ops["spatial_taper"] if ops["1Preg"] else 3 *
+                    ops["smooth_sigma"],
+                )),
             cfRefImg=rigid.phasecorr_reference(
                 refImg=refImg,
-                smooth_sigma=ops['smooth_sigma'],
+                smooth_sigma=ops["smooth_sigma"],
             ),
-            maxregshift=ops['maxregshift'],
-            smooth_sigma_time=ops['smooth_sigma_time'],
+            maxregshift=ops["maxregshift"],
+            smooth_sigma_time=ops["smooth_sigma_time"],
         )
         for frame, dy, dx in zip(frames, ymax, xmax):
             frame[:] = rigid.shift_frame(frame=frame, dy=dy, dx=dx)
@@ -153,14 +157,12 @@ def compute_reference(frames, ops=default_ops()):
         # reset reference image
         refImg = frames[isort].mean(axis=0).astype(np.int16)
         # shift reference image to position of mean shifts
-        refImg = rigid.shift_frame(
-            frame=refImg,
-            dy=int(np.round(-ymax[isort].mean())),
-            dx=int(np.round(-xmax[isort].mean()))
-        )
+        refImg = rigid.shift_frame(frame=refImg, dy=int(np.round(-ymax[isort].mean())),
+                                   dx=int(np.round(-xmax[isort].mean())))
 
     return refImg
 
+
 def compute_reference_masks(refImg, ops=default_ops()):
     ### ------------- compute registration masks ----------------- ###
     if isinstance(refImg, list):
@@ -172,30 +174,33 @@ def compute_reference_masks(refImg, ops=default_ops()):
     else:
         maskMul, maskOffset = rigid.compute_masks(
             refImg=refImg,
-            maskSlope=ops['spatial_taper'] if ops['1Preg'] else 3 * ops['smooth_sigma'],
+            maskSlope=ops["spatial_taper"] if ops["1Preg"] else 3 * ops["smooth_sigma"],
         )
         cfRefImg = rigid.phasecorr_reference(
             refImg=refImg,
-            smooth_sigma=ops['smooth_sigma'],
+            smooth_sigma=ops["smooth_sigma"],
         )
         Ly, Lx = refImg.shape
         blocks = []
-        if ops.get('nonrigid'):
-            blocks = nonrigid.make_blocks(Ly=Ly, Lx=Lx, block_size=ops['block_size'])
+        if ops.get("nonrigid"):
+            blocks = nonrigid.make_blocks(Ly=Ly, Lx=Lx, block_size=ops["block_size"])
 
             maskMulNR, maskOffsetNR, cfRefImgNR = nonrigid.phasecorr_reference(
                 refImg0=refImg,
-                maskSlope=ops['spatial_taper'] if ops['1Preg'] else 3 * ops['smooth_sigma'], # slope of taper mask at the edges
-                smooth_sigma=ops['smooth_sigma'],
+                maskSlope=ops["spatial_taper"] if ops["1Preg"] else 3 *
+                ops["smooth_sigma"],  # slope of taper mask at the edges
+                smooth_sigma=ops["smooth_sigma"],
                 yblock=blocks[0],
                 xblock=blocks[1],
             )
         else:
-            maskMulNR, maskOffsetNR, cfRefImgNR = [], [], [] 
+            maskMulNR, maskOffsetNR, cfRefImgNR = [], [], []
 
         return maskMul, maskOffset, cfRefImg, maskMulNR, maskOffsetNR, cfRefImgNR, blocks
 
-def register_frames(refAndMasks, frames, rmin=-np.inf, rmax=np.inf, bidiphase=0, ops=default_ops(), nZ=1):
+
+def register_frames(refAndMasks, frames, rmin=-np.inf, rmax=np.inf, bidiphase=0,
+                    ops=default_ops(), nZ=1):
     """ register frames to reference image 
     
     Parameters
@@ -215,103 +220,110 @@ def register_frames(refAndMasks, frames, rmin=-np.inf, rmax=np.inf, bidiphase=0,
     --------
 
     ops : dictionary
-        'nframes', 'yoff', 'xoff', 'corrXY', 'yoff1', 'xoff1', 'corrXY1', 'badframes'
+        "nframes", "yoff", "xoff", "corrXY", "yoff1", "xoff1", "corrXY1", "badframes"
 
 
     """
 
     if nZ > 1:
-        cmax_best = -np.inf * np.ones(len(frames), 'float32')
-        cmax_all = -np.inf * np.ones((len(frames), nZ), 'float32')
-        zpos_best = np.zeros(len(frames), 'int')
-        run_nonrigid = ops['nonrigid']
+        cmax_best = -np.inf * np.ones(len(frames), "float32")
+        cmax_all = -np.inf * np.ones((len(frames), nZ), "float32")
+        zpos_best = np.zeros(len(frames), "int")
+        run_nonrigid = ops["nonrigid"]
         for z in range(nZ):
-            ops['nonrigid'] = False
-            outputs = register_frames(refAndMasks[z], frames.copy(), rmin=rmin[z], rmax=rmax[z], 
-                                        bidiphase=bidiphase, ops=ops, nZ=1)
-            cmax_all[:,z] = outputs[3]
-            if z==0:
-                outputs_best = list(outputs[:-4]).copy() 
-            ibest = cmax_best < cmax_all[:,z]
+            ops["nonrigid"] = False
+            outputs = register_frames(refAndMasks[z], frames.copy(), rmin=rmin[z],
+                                      rmax=rmax[z], bidiphase=bidiphase, ops=ops, nZ=1)
+            cmax_all[:, z] = outputs[3]
+            if z == 0:
+                outputs_best = list(outputs[:-4]).copy()
+            ibest = cmax_best < cmax_all[:, z]
             zpos_best[ibest] = z
             cmax_best[ibest] = cmax_all[ibest, z]
             for i, (output_best, output) in enumerate(zip(outputs_best, outputs[:-4])):
                 output_best[ibest] = output[ibest]
         if run_nonrigid:
-            ops['nonrigid'] = True
+            ops["nonrigid"] = True
             nfr = frames.shape[0]
-            for i,z in enumerate(zpos_best):
-                outputs = register_frames(refAndMasks[z], frames[[i]], rmin=rmin[z], rmax=rmax[z],
-                                            bidiphase=bidiphase, ops=ops, nZ=1)
-                
-                if i==0:
+            for i, z in enumerate(zpos_best):
+                outputs = register_frames(refAndMasks[z], frames[[i]], rmin=rmin[z],
+                                          rmax=rmax[z], bidiphase=bidiphase, ops=ops,
+                                          nZ=1)
+
+                if i == 0:
                     outputs_best = []
                     for output in outputs[:-1]:
-                        outputs_best.append(np.zeros((nfr, *output.shape[1:]), dtype=output.dtype))
+                        outputs_best.append(
+                            np.zeros((nfr, *output.shape[1:]), dtype=output.dtype))
                         outputs_best[-1][0] = output[0]
                 else:
                     for output, output_best in zip(outputs[:-1], outputs_best):
                         output_best[i] = output[0]
         frames, ymax, xmax, cmax, ymax1, xmax1, cmax1 = outputs_best
         return frames, ymax, xmax, cmax, ymax1, xmax1, cmax1, (zpos_best, cmax_all)
-    else:    
-        if len(refAndMasks)==7 or not isinstance(refAndMasks, np.ndarray):
-            maskMul, maskOffset, cfRefImg, maskMulNR, maskOffsetNR, cfRefImgNR, blocks = refAndMasks 
+    else:
+        if len(refAndMasks) == 7 or not isinstance(refAndMasks, np.ndarray):
+            maskMul, maskOffset, cfRefImg, maskMulNR, maskOffsetNR, cfRefImgNR, blocks = refAndMasks
         else:
             refImg = refAndMasks
-            if ops.get('norm_frames', False) and 'rmin' not in ops:
-                rmin, rmax = np.int16(np.percentile(refImg,1)), np.int16(np.percentile(refImg,99))
+            if ops.get("norm_frames", False) and "rmin" not in ops:
+                rmin, rmax = np.int16(np.percentile(refImg, 1)), np.int16(
+                    np.percentile(refImg, 99))
                 refImg = np.clip(refImg, rmin, rmax)
-            maskMul, maskOffset, cfRefImg, maskMulNR, maskOffsetNR, cfRefImgNR, blocks = compute_reference_masks(refImg, ops)
-        
+            maskMul, maskOffset, cfRefImg, maskMulNR, maskOffsetNR, cfRefImgNR, blocks = compute_reference_masks(
+                refImg, ops)
+
         if bidiphase != 0:
             bidi.shift(frames, bidiphase)
 
-        
         # if smoothing or filtering or clipping to compute registration shifts, make a copy of the frames
-        dtype = 'float32' if ops['smooth_sigma_time'] > 0 or ops['1Preg'] else frames.dtype
-        fsmooth = frames.copy().astype(dtype) if ops['smooth_sigma_time'] > 0 or ops['1Preg'] else frames
-        
-        if ops['smooth_sigma_time']:
-            fsmooth = utils.temporal_smooth(data=fsmooth, sigma=ops['smooth_sigma_time'])
+        dtype = "float32" if ops["smooth_sigma_time"] > 0 or ops[
+            "1Preg"] else frames.dtype
+        fsmooth = frames.copy().astype(
+            dtype) if ops["smooth_sigma_time"] > 0 or ops["1Preg"] else frames
+
+        if ops["smooth_sigma_time"]:
+            fsmooth = utils.temporal_smooth(data=fsmooth,
+                                            sigma=ops["smooth_sigma_time"])
         else:
             fsmooth = frames
 
         # preprocessing for 1P recordings
-        if ops['1Preg']:
-            if ops['pre_smooth']:
-                fsmooth = utils.spatial_smooth(fsmooth, int(ops['pre_smooth']))
-            fsmooth = utils.spatial_high_pass(fsmooth, int(ops['spatial_hp_reg']))
+        if ops["1Preg"]:
+            if ops["pre_smooth"]:
+                fsmooth = utils.spatial_smooth(fsmooth, int(ops["pre_smooth"]))
+            fsmooth = utils.spatial_high_pass(fsmooth, int(ops["spatial_hp_reg"]))
 
         # rigid registration
         ymax, xmax, cmax = rigid.phasecorr(
-            data=rigid.apply_masks(data=np.clip(fsmooth, rmin, rmax) if rmin>-np.inf else fsmooth, 
-                                    maskMul=maskMul, maskOffset=maskOffset),
+            data=rigid.apply_masks(
+                data=np.clip(fsmooth, rmin, rmax) if rmin > -np.inf else fsmooth,
+                maskMul=maskMul, maskOffset=maskOffset),
             cfRefImg=cfRefImg,
-            maxregshift=ops['maxregshift'],
-            smooth_sigma_time=ops['smooth_sigma_time'],
+            maxregshift=ops["maxregshift"],
+            smooth_sigma_time=ops["smooth_sigma_time"],
         )
-        
+
         for frame, dy, dx in zip(frames, ymax, xmax):
             frame[:] = rigid.shift_frame(frame=frame, dy=dy, dx=dx)
-        
+
         # non-rigid registration
-        if ops['nonrigid']:
+        if ops["nonrigid"]:
             # need to also shift smoothed/filtered data
-            if ops['smooth_sigma_time'] or ops['1Preg']:
+            if ops["smooth_sigma_time"] or ops["1Preg"]:
                 for fsm, dy, dx in zip(fsmooth, ymax, xmax):
                     fsm[:] = rigid.shift_frame(frame=fsm, dy=dy, dx=dx)
-                    
+
             ymax1, xmax1, cmax1 = nonrigid.phasecorr(
-                data=np.clip(fsmooth, rmin, rmax) if rmin>-np.inf else fsmooth,
+                data=np.clip(fsmooth, rmin, rmax) if rmin > -np.inf else fsmooth,
                 maskMul=maskMulNR.squeeze(),
                 maskOffset=maskOffsetNR.squeeze(),
                 cfRefImg=cfRefImgNR.squeeze(),
-                snr_thresh=ops['snr_thresh'],
+                snr_thresh=ops["snr_thresh"],
                 NRsm=blocks[-1],
                 xblock=blocks[1],
                 yblock=blocks[0],
-                maxregshiftNR=ops['maxregshiftNR'],
+                maxregshiftNR=ops["maxregshiftNR"],
             )
 
             frames = nonrigid.transform_data(
@@ -323,171 +335,184 @@ def register_frames(refAndMasks, frames, rmin=-np.inf, rmax=np.inf, bidiphase=0,
                 xmax1=xmax1,
             )
         else:
-            ymax1, xmax1, cmax1 = None, None, None 
-        
+            ymax1, xmax1, cmax1 = None, None, None
+
         return frames, ymax, xmax, cmax, ymax1, xmax1, cmax1, None
 
+
 def shift_frames(frames, yoff, xoff, yoff1, xoff1, blocks=None, ops=default_ops()):
-    if ops['bidiphase'] != 0 and not ops['bidi_corrected']:
-        bidi.shift(frames, int(ops['bidiphase']))
-    
+    if ops["bidiphase"] != 0 and not ops["bidi_corrected"]:
+        bidi.shift(frames, int(ops["bidiphase"]))
+
     for frame, dy, dx in zip(frames, yoff, xoff):
         frame[:] = rigid.shift_frame(frame=frame, dy=dy, dx=dx)
 
-    if ops['nonrigid']:
-        frames = nonrigid.transform_data(frames, yblock=blocks[0], xblock=blocks[1], nblocks=blocks[2],
-                                         ymax1=yoff1, xmax1=xoff1, bilinear=ops.get('bilinear_reg', True))
+    if ops["nonrigid"]:
+        frames = nonrigid.transform_data(frames, yblock=blocks[0], xblock=blocks[1],
+                                         nblocks=blocks[2], ymax1=yoff1, xmax1=xoff1,
+                                         bilinear=ops.get("bilinear_reg", True))
     return frames
 
+
 def normalize_reference_image(refImg):
     if isinstance(refImg, list):
         rmins = []
         rmaxs = []
         for rimg in refImg:
-            rmin, rmax = np.int16(np.percentile(rimg,1)), np.int16(np.percentile(rimg,99))
+            rmin, rmax = np.int16(np.percentile(rimg,
+                                                1)), np.int16(np.percentile(rimg, 99))
             rimg[:] = np.clip(rimg, rmin, rmax)
             rmins.append(rmin)
             rmaxs.append(rmax)
         return refImg, rmins, rmaxs
     else:
-        rmin, rmax = np.int16(np.percentile(refImg,1)), np.int16(np.percentile(refImg,99))
+        rmin, rmax = np.int16(np.percentile(refImg,
+                                            1)), np.int16(np.percentile(refImg, 99))
         refImg = np.clip(refImg, rmin, rmax)
         return refImg, rmin, rmax
 
-def compute_reference_and_register_frames(f_align_in, f_align_out=None, refImg=None, ops=default_ops()):
+
+def compute_reference_and_register_frames(f_align_in, f_align_out=None, refImg=None,
+                                          ops=default_ops()):
     """ compute reference frame, if refImg is None, and align frames in f_align_in to reference 
     
     if f_align_out is not None, registered frames are written to f_align_out
 
-    f_align_in, f_align_out can be a BinaryRWFile or any type of array that can be slice-indexed
+    f_align_in, f_align_out can be a BinaryFile or any type of array that can be slice-indexed
     
     """
-    
+
     n_frames, Ly, Lx = f_align_in.shape
-    
-    batch_size = ops['batch_size']
+
+    batch_size = ops["batch_size"]
     ### ----- compute reference image and bidiphase shift -------------- ###
     if refImg is None:
         # grab frames
-        frames = f_align_in[np.linspace(0, n_frames, 1 + np.minimum(ops['nimg_init'], n_frames), dtype=int)[:-1]]    
+        frames = f_align_in[np.linspace(0, n_frames,
+                                        1 + np.minimum(ops["nimg_init"], n_frames),
+                                        dtype=int)[:-1]]
         # compute bidiphase shift
-        if ops['do_bidiphase'] and ops['bidiphase'] == 0 and not ops['bidi_corrected']:
+        if ops["do_bidiphase"] and ops["bidiphase"] == 0 and not ops["bidi_corrected"]:
             bidiphase = bidi.compute(frames)
-            print('NOTE: estimated bidiphase offset from data: %d pixels' % bidiphase)
-            ops['bidiphase'] = bidiphase
+            print("NOTE: estimated bidiphase offset from data: %d pixels" % bidiphase)
+            ops["bidiphase"] = bidiphase
             # shift frames
             if bidiphase != 0:
-                bidi.shift(frames, int(ops['bidiphase']))
+                bidi.shift(frames, int(ops["bidiphase"]))
         else:
             bidiphase = 0
 
         if refImg is None:
             t0 = time.time()
             refImg = compute_reference(frames, ops=ops)
-            print('Reference frame, %0.2f sec.'%(time.time()-t0))
-    
+            print("Reference frame, %0.2f sec." % (time.time() - t0))
+
     if isinstance(refImg, list):
         nZ = len(refImg)
-        print(f'List of reference frames len = {nZ}')
+        print(f"List of reference frames len = {nZ}")
     else:
         nZ = 1
 
     # normalize reference image
     refImg_orig = refImg.copy()
-    if ops.get('norm_frames', False):
+    if ops.get("norm_frames", False):
         refImg, rmin, rmax = normalize_reference_image(refImg)
     else:
-        if nZ==1:
+        if nZ == 1:
             rmin, rmax = -np.inf, np.inf
         else:
             rmin = -np.inf * np.ones(nZ)
             rmax = np.inf * np.ones(nZ)
 
-    if ops['bidiphase'] and not ops['bidi_corrected']:
-        bidiphase = int(ops['bidiphase'])
+    if ops["bidiphase"] and not ops["bidi_corrected"]:
+        bidiphase = int(ops["bidiphase"])
     else:
         bidiphase = 0
 
     refAndMasks = compute_reference_masks(refImg, ops)
-    
+
     ### ------------- register frames to reference image ------------ ###
 
-    mean_img = np.zeros((Ly, Lx), 'float32')
+    mean_img = np.zeros((Ly, Lx), "float32")
     rigid_offsets, nonrigid_offsets, zpos, cmax_all = [], [], [], []
 
-    if ops['frames_include'] != -1:
-        n_frames = min(n_frames, ops['frames_include'])
+    if ops["frames_include"] != -1:
+        n_frames = min(n_frames, ops["frames_include"])
 
     t0 = time.time()
-    
+
     for k in np.arange(0, n_frames, batch_size):
-        frames = f_align_in[k : min(k + batch_size, n_frames)]
-        frames, ymax, xmax, cmax, ymax1, xmax1, cmax1, zest = register_frames(refAndMasks, frames, 
-                                                                                rmin=rmin, rmax=rmax, 
-                                                                                bidiphase=bidiphase, 
-                                                                                ops=ops,
-                                                                                nZ=nZ)
+        frames = f_align_in[k:min(k + batch_size, n_frames)]
+        frames, ymax, xmax, cmax, ymax1, xmax1, cmax1, zest = register_frames(
+            refAndMasks, frames, rmin=rmin, rmax=rmax, bidiphase=bidiphase, ops=ops,
+            nZ=nZ)
         rigid_offsets.append([ymax, xmax, cmax])
         if zest is not None:
             zpos.extend(list(zest[0]))
             cmax_all.extend(list(zest[1]))
-        if ops['nonrigid']:
+        if ops["nonrigid"]:
             nonrigid_offsets.append([ymax1, xmax1, cmax1])
 
         mean_img += frames.sum(axis=0) / n_frames
 
         if f_align_out is None:
-            f_align_in[k : min(k + batch_size, n_frames)] = frames
+            f_align_in[k:min(k + batch_size, n_frames)] = frames
         else:
-            f_align_out[k : min(k + batch_size, n_frames)] = frames
-            
-        if (ops['reg_tif'] if ops['functional_chan'] == ops['align_by_chan'] else ops['reg_tif_chan2']):
-            fname = io.generate_tiff_filename(
-                functional_chan=ops['functional_chan'],
-                align_by_chan=ops['align_by_chan'],
-                save_path=ops['save_path'],
-                k=k,
-                ichan=True
-            )
+            f_align_out[k:min(k + batch_size, n_frames)] = frames
+
+        if (ops["reg_tif"] if ops["functional_chan"] == ops["align_by_chan"] else
+                ops["reg_tif_chan2"]):
+            fname = io.generate_tiff_filename(functional_chan=ops["functional_chan"],
+                                              align_by_chan=ops["align_by_chan"],
+                                              save_path=ops["save_path"], k=k,
+                                              ichan=True)
             io.save_tiff(mov=frames, fname=fname)
-        
-        print('Registered %d/%d in %0.2fs'%(k+frames.shape[0], n_frames, time.time()-t0))
+
+        print("Registered %d/%d in %0.2fs" %
+              (k + frames.shape[0], n_frames, time.time() - t0))
     rigid_offsets = utils.combine_offsets_across_batches(rigid_offsets, rigid=True)
-    if ops['nonrigid']:
-        nonrigid_offsets = utils.combine_offsets_across_batches(nonrigid_offsets, rigid=False)
-    
-    return refImg_orig, rmin, rmax, mean_img, rigid_offsets, nonrigid_offsets, (zpos, cmax_all)
+    if ops["nonrigid"]:
+        nonrigid_offsets = utils.combine_offsets_across_batches(
+            nonrigid_offsets, rigid=False)
+
+    return refImg_orig, rmin, rmax, mean_img, rigid_offsets, nonrigid_offsets, (
+        zpos, cmax_all)
+
 
-def shift_frames_and_write(f_alt_in, f_alt_out=None, yoff=None, xoff=None, yoff1=None, xoff1=None, ops=default_ops()):
+def shift_frames_and_write(f_alt_in, f_alt_out=None, yoff=None, xoff=None, yoff1=None,
+                           xoff1=None, ops=default_ops()):
     """ shift frames for alternate channel in f_alt_in and write to f_alt_out if not None (else write to f_alt_in) """
     n_frames, Ly, Lx = f_alt_in.shape
     if yoff is None or xoff is None:
-        raise ValueError('no rigid registration offsets provided')
+        raise ValueError("no rigid registration offsets provided")
     elif yoff.shape[0] != n_frames or xoff.shape[0] != n_frames:
-        raise ValueError('rigid registration offsets are not the same size as input frames')
-    # Overwrite blocks if nonrigid registration is activated   
+        raise ValueError(
+            "rigid registration offsets are not the same size as input frames")
+    # Overwrite blocks if nonrigid registration is activated
     blocks = None
-    if ops.get('nonrigid'):
+    if ops.get("nonrigid"):
         if yoff1 is None or xoff1 is None:
-            raise ValueError('nonrigid registration is activated but no nonrigid shifts provided')
+            raise ValueError(
+                "nonrigid registration is activated but no nonrigid shifts provided")
         elif yoff1.shape[0] != n_frames or xoff1.shape[0] != n_frames:
-            raise ValueError('nonrigid registration offsets are not the same size as input frames')
+            raise ValueError(
+                "nonrigid registration offsets are not the same size as input frames")
 
-        blocks = nonrigid.make_blocks(Ly=Ly, Lx=Lx, block_size=ops['block_size'])
+        blocks = nonrigid.make_blocks(Ly=Ly, Lx=Lx, block_size=ops["block_size"])
 
-    if ops['frames_include'] != -1:
-        n_frames = min(n_frames, ops['frames_include'])
+    if ops["frames_include"] != -1:
+        n_frames = min(n_frames, ops["frames_include"])
 
-    mean_img = np.zeros((Ly, Lx), 'float32')
-    batch_size = ops['batch_size']
+    mean_img = np.zeros((Ly, Lx), "float32")
+    batch_size = ops["batch_size"]
     t0 = time.time()
     for k in np.arange(0, n_frames, batch_size):
-        frames = f_alt_in[k : min(k + batch_size, n_frames)].astype('float32')
-        yoffk = yoff[k : min(k + batch_size, n_frames)].astype(int)
-        xoffk = xoff[k : min(k + batch_size, n_frames)].astype(int)
-        if ops.get('nonrigid'):
-            yoff1k = yoff1[k : min(k + batch_size, n_frames)]
-            xoff1k = xoff1[k : min(k + batch_size, n_frames)]
+        frames = f_alt_in[k:min(k + batch_size, n_frames)].astype("float32")
+        yoffk = yoff[k:min(k + batch_size, n_frames)].astype(int)
+        xoffk = xoff[k:min(k + batch_size, n_frames)].astype(int)
+        if ops.get("nonrigid"):
+            yoff1k = yoff1[k:min(k + batch_size, n_frames)]
+            xoff1k = xoff1[k:min(k + batch_size, n_frames)]
         else:
             yoff1k, xoff1k = None, None
 
@@ -495,54 +520,54 @@ def shift_frames_and_write(f_alt_in, f_alt_out=None, yoff=None, xoff=None, yoff1
         mean_img += frames.sum(axis=0) / n_frames
 
         if f_alt_out is None:
-            f_alt_in[k : min(k + batch_size, n_frames)] = frames
+            f_alt_in[k:min(k + batch_size, n_frames)] = frames
         else:
-            f_alt_out[k : min(k + batch_size, n_frames)] = frames
-                
-        if (ops['reg_tif_chan2'] if ops['functional_chan'] == ops['align_by_chan'] else ops['reg_tif']):
-            fname = io.generate_tiff_filename(
-                functional_chan=ops['functional_chan'],
-                align_by_chan=ops['align_by_chan'],
-                save_path=ops['save_path'],
-                k=k,
-                ichan=False
-            )
+            f_alt_out[k:min(k + batch_size, n_frames)] = frames
+
+        if (ops["reg_tif_chan2"]
+                if ops["functional_chan"] == ops["align_by_chan"] else ops["reg_tif"]):
+            fname = io.generate_tiff_filename(functional_chan=ops["functional_chan"],
+                                              align_by_chan=ops["align_by_chan"],
+                                              save_path=ops["save_path"], k=k,
+                                              ichan=False)
             io.save_tiff(mov=frames, fname=fname)
 
-        print('Second channel, Registered %d/%d in %0.2fs'%(k+frames.shape[0], n_frames, time.time()-t0))
+        print("Second channel, Registered %d/%d in %0.2fs" %
+              (k + frames.shape[0], n_frames, time.time() - t0))
 
-    return mean_img  
+    return mean_img
 
 
-def registration_wrapper(f_reg, f_raw=None, f_reg_chan2=None, f_raw_chan2=None, refImg=None, align_by_chan2=False, ops=default_ops()):
+def registration_wrapper(f_reg, f_raw=None, f_reg_chan2=None, f_raw_chan2=None,
+                         refImg=None, align_by_chan2=False, ops=default_ops()):
     """ main registration function
 
     if f_raw is not None, f_raw is read and registered and saved to f_reg
     if f_raw_chan2 is not None, f_raw_chan2 is read and registered and saved to f_reg_chan2
 
-    the registration shifts are computed on chan2 if ops['functional_chan'] != ops['align_by_chan']
+    the registration shifts are computed on chan2 if ops["functional_chan"] != ops["align_by_chan"]
 
 
     Parameters
     ----------------
 
-    f_reg : array of registered functional frames, np.ndarray or io.BinaryRWFile
+    f_reg : array of registered functional frames, np.ndarray or io.BinaryFile
         n_frames x Ly x Lx
 
-    f_raw : array of raw functional frames, np.ndarray or io.BinaryRWFile
+    f_raw : array of raw functional frames, np.ndarray or io.BinaryFile
         n_frames x Ly x Lx
 
-    f_reg_chan2 : array of registered anatomical frames, np.ndarray or io.BinaryRWFile
+    f_reg_chan2 : array of registered anatomical frames, np.ndarray or io.BinaryFile
         n_frames x Ly x Lx
 
-    f_raw_chan2 : array of raw anatomical frames, np.ndarray or io.BinaryRWFile
+    f_raw_chan2 : array of raw anatomical frames, np.ndarray or io.BinaryFile
         n_frames x Ly x Lx
 
     refImg : 2D array, int16
         size [Ly x Lx], initial reference image
 
     align_by_chan2: boolean
-        whether you'd like to align by non-functional channel
+        whether you"d like to align by non-functional channel
 
     ops : dictionary or list of dicts
         dictionary containing input arguments for suite2p pipeline
@@ -595,7 +620,7 @@ def registration_wrapper(f_reg, f_raw=None, f_reg_chan2=None, f_raw_chan2=None,
             f_alt_out = f_reg_chan2
     else:
         if f_raw is None:
-            f_align_in = f_reg_chan2 
+            f_align_in = f_reg_chan2
             f_alt_in = f_reg
         else:
             f_align_in = f_raw_chan2
@@ -603,234 +628,151 @@ def registration_wrapper(f_reg, f_raw=None, f_reg_chan2=None, f_raw_chan2=None,
             f_align_out = f_reg_chan2
             f_alt_out = f_reg
 
-
     n_frames, Ly, Lx = f_align_in.shape
     if f_alt_in is not None and f_alt_in.shape[0] == f_align_in.shape[0]:
         nchannels = 2
-        print('registering two channels')
+        print("registering two channels")
     else:
         nchannels = 1
 
-    outputs = compute_reference_and_register_frames(f_align_in, f_align_out=f_align_out, refImg=refImg, ops=ops)
+    outputs = compute_reference_and_register_frames(f_align_in, f_align_out=f_align_out,
+                                                    refImg=refImg, ops=ops)
     refImg, rmin, rmax, mean_img, rigid_offsets, nonrigid_offsets, zest = outputs
     yoff, xoff, corrXY = rigid_offsets
 
-            
-    if ops['nonrigid']:
-            yoff1, xoff1, corrXY1 = nonrigid_offsets
+    if ops["nonrigid"]:
+        yoff1, xoff1, corrXY1 = nonrigid_offsets
     else:
         yoff1, xoff1, corryXY1 = None, None, None
 
     if nchannels > 1:
-        mean_img_alt = shift_frames_and_write(f_alt_in, f_alt_out, yoff, xoff, yoff1, xoff1, ops)
+        mean_img_alt = shift_frames_and_write(f_alt_in, f_alt_out, yoff, xoff, yoff1,
+                                              xoff1, ops)
     else:
         mean_img_alt = None
 
-    if nchannels==1 or not align_by_chan2:
+    if nchannels == 1 or not align_by_chan2:
         meanImg = mean_img
-        if nchannels==2:
+        if nchannels == 2:
             meanImg_chan2 = mean_img_alt
         else:
             meanImg_chan2 = None
     elif nchannels == 2:
         meanImg_chan2 = mean_img
         meanImg = mean_img_alt
-            
-        
+
     # compute valid region
-    badframes = np.zeros(n_frames, 'bool')
-    if 'data_path' in ops and len(ops['data_path']) > 0:
-        badfrfile = path.abspath(path.join(ops['data_path'][0], 'bad_frames.npy'))
+    badframes = np.zeros(n_frames, "bool")
+    if "data_path" in ops and len(ops["data_path"]) > 0:
+        badfrfile = path.abspath(path.join(ops["data_path"][0], "bad_frames.npy"))
         # Check if badframes file exists
         if path.isfile(badfrfile):
-            print('bad frames file path: %s'%badfrfile)
+            print("bad frames file path: %s" % badfrfile)
             bf_indices = np.load(badfrfile)
             bf_indices = bf_indices.flatten().astype(int)
             # Set indices of badframes to true
             badframes[bf_indices] = True
-            print('number of badframes: %d'%badframes.sum())
+            print("number of badframes: %d" % badframes.sum())
 
     # return frames which fall outside range
     badframes, yrange, xrange = compute_crop(
         xoff=xoff,
         yoff=yoff,
         corrXY=corrXY,
-        th_badframes=ops['th_badframes'],
+        th_badframes=ops["th_badframes"],
         badframes=badframes,
-        maxregshift=ops['maxregshift'],
+        maxregshift=ops["maxregshift"],
         Ly=Ly,
         Lx=Lx,
     )
 
     return refImg, rmin, rmax, meanImg, rigid_offsets, nonrigid_offsets, zest, meanImg_chan2, badframes, yrange, xrange
 
-def register_binary(ops: Dict[str, Any], refImg=None, raw=True):
-    """ main registration function
-
-    Parameters
-    ----------
-
-    ops : dictionary or list of dicts
-        'Ly', 'Lx', 'batch_size', 'align_by_chan', 'nonrigid'
-        (optional 'keep_movie_raw', 'raw_file')
-
-    refImg : 2D array (optional, default None)
-
-    raw : bool (optional, default True)
-        use raw_file for registration if available, if False forces reg_file to be used
-
-    Returns
-    --------
-
-    ops : dictionary
-        'nframes', 'yoff', 'xoff', 'corrXY', 'yoff1', 'xoff1', 'corrXY1', 'badframes'
-
-
-    """
-    Ly, Lx = ops['Ly'], ops['Lx']
-    n_frames = ops['nframes']
-    print('registering %d frames'%ops['nframes'])
-    
-    # get binary file paths
-    raw = raw and ops.get('keep_movie_raw') and 'raw_file' in ops and path.isfile(ops['raw_file'])
-    reg_file_align = ops['reg_file'] if (ops['nchannels'] < 2 or ops['functional_chan'] == ops['align_by_chan']) else ops['reg_file_chan2']
-    if raw:
-        raw_file_align = ops.get('raw_file') if (ops['nchannels'] < 2 or ops['functional_chan'] == ops['align_by_chan']) else ops.get('raw_file_chan2')
-    else:
-        raw_file_align = None
-        if ops['do_bidiphase'] and ops['bidiphase'] != 0:
-            ops['bidi_corrected'] = True
-
-    if ops['nchannels'] > 1:
-        reg_file_alt = ops['reg_file_chan2'] if ops['functional_chan'] == ops['align_by_chan'] else ops['reg_file']
-        raw_file_alt = ops.get('raw_file_chan2') if ops['functional_chan'] == ops['align_by_chan'] else ops.get('raw_file')
-        raw_file_alt = raw_file_alt if raw else []
-    else:
-        reg_file_alt = reg_file_align 
-        raw_file_alt = reg_file_align
-
-    with io.BinaryRWFile(Ly=Ly, Lx=Lx, filename=raw_file_align if raw else reg_file_align) as f_align_in, \
-         io.BinaryRWFile(Ly=Ly, Lx=Lx, filename=reg_file_align) as f_align_out, \
-         io.BinaryRWFile(Ly=Ly, Lx=Lx, filename=raw_file_alt if raw else reg_file_alt) as f_alt_in,\
-         io.BinaryRWFile(Ly=Ly, Lx=Lx, filename=reg_file_alt) as f_alt_out:         
-        if not raw:
-            f_align_out.close()
-            f_align_out = None
-            f_alt_out.close()
-            f_alt_out = None
-        if ops['nchannels'] == 1:
-            f_alt_in.close() 
-            f_alt_in = None
-        
-        outputs = registration_wrapper(f_align_out, f_align_in, f_alt_out, f_alt_in, refImg, ops=ops)
-        
-    # refImg, rmin, rmax, mean_img, rigid_offsets, nonrigid_offsets, zpos, mean_img_alt, badframes, yrange, xrange = outputs
-
-    # # assign reference image and normalizers
-    # ops['refImg'] = refImg 
-    # ops['rmin'], ops['rmax'] = rmin, rmax
-    # # assign rigid offsets to ops
-    # ops['yoff'], ops['xoff'], ops['corrXY'] = rigid_offsets
-    # # assign nonrigid offsets to ops
-    # ops['yoff1'], ops['xoff1'], ops['corrXY1'] = nonrigid_offsets
-    # # assign mean images
-    # if ops['nchannels'] == 1 or ops['functional_chan'] == ops['align_by_chan']:
-    #     ops['meanImg'] = mean_img 
-    # elif ops['nchannels'] == 2:
-    #     ops['meanImg_chan2'] = mean_img_alt
-    # # assign crop computation and badframes
-    # ops['badframes'], ops['yrange'], ops['xrange'] = badframes, yrange, xrange
-    
-    ops = save_registration_outputs_to_ops(outputs, ops)
-
-    # add enhanced mean image
-    ops = enhanced_mean_image(ops)
-
-    return ops
-
 
 def save_registration_outputs_to_ops(registration_outputs, ops):
 
     refImg, rmin, rmax, meanImg, rigid_offsets, nonrigid_offsets, zest, meanImg_chan2, badframes, yrange, xrange = registration_outputs
     # assign reference image and normalizers
-    ops['refImg'] = refImg 
-    ops['rmin'], ops['rmax'] = rmin, rmax
+    ops["refImg"] = refImg
+    ops["rmin"], ops["rmax"] = rmin, rmax
     # assign rigid offsets to ops
-    ops['yoff'], ops['xoff'], ops['corrXY'] = rigid_offsets
+    ops["yoff"], ops["xoff"], ops["corrXY"] = rigid_offsets
     # assign nonrigid offsets to ops
-    if ops['nonrigid']:
-        ops['yoff1'], ops['xoff1'], ops['corrXY1'] = nonrigid_offsets
+    if ops["nonrigid"]:
+        ops["yoff1"], ops["xoff1"], ops["corrXY1"] = nonrigid_offsets
     # assign mean images
-    ops['meanImg'] = meanImg
+    ops["meanImg"] = meanImg
     if meanImg_chan2 is not None:
-        ops['meanImg_chan2'] = meanImg_chan2
+        ops["meanImg_chan2"] = meanImg_chan2
     # assign crop computation and badframes
-    ops['badframes'], ops['yrange'], ops['xrange'] = badframes, yrange, xrange
+    ops["badframes"], ops["yrange"], ops["xrange"] = badframes, yrange, xrange
     if len(zest[0]) > 0:
-        ops['zpos_registration'] = np.array(zest[0])
-        ops['cmax_registration'] = np.array(zest[1])
+        ops["zpos_registration"] = np.array(zest[0])
+        ops["cmax_registration"] = np.array(zest[1])
     return ops
-            
+
 
 def enhanced_mean_image(ops):
     """ computes enhanced mean image and adds it to ops
 
-    Median filters ops['meanImg'] with 4*diameter in 2D and subtracts and
+    Median filters ops["meanImg"] with 4*diameter in 2D and subtracts and
     divides by this median-filtered image to return a high-pass filtered
-    image ops['meanImgE']
+    image ops["meanImgE"]
 
     Parameters
     ----------
     ops : dictionary
-        uses 'meanImg', 'aspect', 'spatscale_pix', 'yrange' and 'xrange'
+        uses "meanImg", "aspect", "spatscale_pix", "yrange" and "xrange"
 
     Returns
     -------
         ops : dictionary
-            'meanImgE' field added
+            "meanImgE" field added
 
     """
 
-    I = ops['meanImg'].astype(np.float32)
+    I = ops["meanImg"].astype(np.float32)
     mimg0 = compute_enhanced_mean_image(I, ops)
-    #mimg = mimg0.min() * np.ones((ops['Ly'],ops['Lx']),np.float32)
-    #mimg[ops['yrange'][0]:ops['yrange'][1],
-    #    ops['xrange'][0]:ops['xrange'][1]] = mimg0
-    ops['meanImgE'] = mimg0
-    print('added enhanced mean image')
+    #mimg = mimg0.min() * np.ones((ops["Ly"],ops["Lx"]),np.float32)
+    #mimg[ops["yrange"][0]:ops["yrange"][1],
+    #    ops["xrange"][0]:ops["xrange"][1]] = mimg0
+    ops["meanImgE"] = mimg0
+    print("added enhanced mean image")
     return ops
 
+
 def compute_enhanced_mean_image(I, ops):
     """ computes enhanced mean image
 
-    Median filters ops['meanImg'] with 4*diameter in 2D and subtracts and
+    Median filters ops["meanImg"] with 4*diameter in 2D and subtracts and
     divides by this median-filtered image to return a high-pass filtered
-    image ops['meanImgE']
+    image ops["meanImgE"]
 
     Parameters
     ----------
     ops : dictionary
-        uses 'meanImg', 'aspect', 'spatscale_pix', 'yrange' and 'xrange'
+        uses "meanImg", "aspect", "spatscale_pix", "yrange" and "xrange"
 
     Returns
     -------
         ops : dictionary
-            'meanImgE' field added
+            "meanImgE" field added
 
     """
 
-    I = ops['meanImg'].astype(np.float32)
-    if 'spatscale_pix' not in ops:
-        if isinstance(ops['diameter'], int):
-            diameter = np.array([ops['diameter'], ops['diameter']])
+    I = ops["meanImg"].astype(np.float32)
+    if "spatscale_pix" not in ops:
+        if isinstance(ops["diameter"], int):
+            diameter = np.array([ops["diameter"], ops["diameter"]])
         else:
-            diameter = np.array(ops['diameter'])
-        if diameter[0]==0:
+            diameter = np.array(ops["diameter"])
+        if diameter[0] == 0:
             diameter[:] = 12
-        ops['spatscale_pix'] = diameter[1]
-        ops['aspect'] = diameter[0]/diameter[1]
+        ops["spatscale_pix"] = diameter[1]
+        ops["aspect"] = diameter[0] / diameter[1]
 
-    diameter = 4*np.ceil(np.array([ops['spatscale_pix'] * ops['aspect'], ops['spatscale_pix']])) + 1
+    diameter = 4 * np.ceil(
+        np.array([ops["spatscale_pix"] * ops["aspect"], ops["spatscale_pix"]])) + 1
     diameter = diameter.flatten().astype(np.int64)
     Imed = medfilt2d(I, [diameter[0], diameter[1]])
     I = I - Imed
@@ -841,5 +783,5 @@ def compute_enhanced_mean_image(I, ops):
     mimg0 = I
 
     mimg0 = (mimg0 - mimg1) / (mimg99 - mimg1)
-    mimg0 = np.maximum(0,np.minimum(1,mimg0))
-    return mimg0
\ No newline at end of file
+    mimg0 = np.maximum(0, np.minimum(1, mimg0))
+    return mimg0
diff --git a/suite2p/registration/rigid.py b/suite2p/registration/rigid.py
index 4a2278694..b68a65b09 100644
--- a/suite2p/registration/rigid.py
+++ b/suite2p/registration/rigid.py
@@ -25,12 +25,13 @@ def compute_masks(refImg, maskSlope) -> Tuple[np.ndarray, np.ndarray]:
     Ly, Lx = refImg.shape
     maskMul = spatial_taper(maskSlope, Ly, Lx)
     maskOffset = refImg.mean() * (1. - maskMul)
-    return maskMul.astype('float32'), maskOffset.astype('float32')
+    return maskMul.astype("float32"), maskOffset.astype("float32")
 
 
-def apply_masks(data: np.ndarray, maskMul: np.ndarray, maskOffset: np.ndarray) -> np.ndarray:
+def apply_masks(data: np.ndarray, maskMul: np.ndarray,
+                maskOffset: np.ndarray) -> np.ndarray:
     """
-    Returns a 3D image 'data', multiplied by 'maskMul' and then added 'maskOffet'.
+    Returns a 3D image "data", multiplied by "maskMul" and then added "maskOffet".
 
     Parameters
     ----------
@@ -47,8 +48,8 @@ def apply_masks(data: np.ndarray, maskMul: np.ndarray, maskOffset: np.ndarray) -
 
 def phasecorr_reference(refImg: np.ndarray, smooth_sigma=None) -> np.ndarray:
     """
-    Returns reference image fft'ed and complex conjugate and multiplied by gaussian filter in the fft domain,
-    with standard deviation 'smooth_sigma' computes fft'ed reference image for phasecorr.
+    Returns reference image fft"ed and complex conjugate and multiplied by gaussian filter in the fft domain,
+    with standard deviation "smooth_sigma" computes fft"ed reference image for phasecorr.
 
     Parameters
     ----------
@@ -62,7 +63,8 @@ def phasecorr_reference(refImg: np.ndarray, smooth_sigma=None) -> np.ndarray:
     cfRefImg = complex_fft2(img=refImg)
     cfRefImg /= (1e-5 + np.absolute(cfRefImg))
     cfRefImg *= gaussian_fft(smooth_sigma, cfRefImg.shape[0], cfRefImg.shape[1])
-    return cfRefImg.astype('complex64')
+    return cfRefImg.astype("complex64")
+
 
 def phasecorr(data, cfRefImg, maxregshift, smooth_sigma_time) -> Tuple[int, int, float]:
     """ compute phase correlation between data and reference image
@@ -70,7 +72,7 @@ def phasecorr(data, cfRefImg, maxregshift, smooth_sigma_time) -> Tuple[int, int,
     Parameters
     ----------
     data : int16
-        array that's frames x Ly x Lx
+        array that"s frames x Ly x Lx
     maxregshift : float
         maximum shift as a fraction of the minimum dimension of data (min(Ly,Lx) * maxregshift)
     smooth_sigma_time : float
@@ -88,20 +90,19 @@ def phasecorr(data, cfRefImg, maxregshift, smooth_sigma_time) -> Tuple[int, int,
     """
     min_dim = np.minimum(*data.shape[1:])  # maximum registration shift allowed
     lcorr = int(np.minimum(np.round(maxregshift * min_dim), min_dim // 2))
-    
+
     #cc = convolve(data, cfRefImg, lcorr)
     data = convolve(data, cfRefImg)
-    cc = np.real(np.block(
-                [[data[:,  -lcorr:, -lcorr:], data[:,  -lcorr:, :lcorr+1]],
-                [data[:, :lcorr+1, -lcorr:], data[:, :lcorr+1, :lcorr+1]]]
-            )
-            )
-        
+    cc = np.real(
+        np.block([[data[:, -lcorr:, -lcorr:], data[:, -lcorr:, :lcorr + 1]],
+                  [data[:, :lcorr + 1, -lcorr:], data[:, :lcorr + 1, :lcorr + 1]]]))
+
     cc = temporal_smooth(cc, smooth_sigma_time) if smooth_sigma_time > 0 else cc
 
     ymax, xmax = np.zeros(data.shape[0], np.int32), np.zeros(data.shape[0], np.int32)
     for t in np.arange(data.shape[0]):
-        ymax[t], xmax[t] = np.unravel_index(np.argmax(cc[t], axis=None), (2 * lcorr + 1, 2 * lcorr + 1))
+        ymax[t], xmax[t] = np.unravel_index(np.argmax(cc[t], axis=None),
+                                            (2 * lcorr + 1, 2 * lcorr + 1))
     cmax = cc[np.arange(len(cc)), ymax, xmax]
     ymax, xmax = ymax - lcorr, xmax - lcorr
 
diff --git a/suite2p/registration/utils.py b/suite2p/registration/utils.py
index ae5039f20..1a6d76cd6 100644
--- a/suite2p/registration/utils.py
+++ b/suite2p/registration/utils.py
@@ -4,19 +4,18 @@
 
 import numpy as np
 from numba import vectorize, complex64
-from numpy.fft import ifftshift#, fft2, ifft2
-from scipy.fft import next_fast_len#, fft2, ifft2
+from numpy.fft import ifftshift  #, fft2, ifft2
+from scipy.fft import next_fast_len  #, fft2, ifft2
 from scipy.ndimage import gaussian_filter1d
 import torch
 
-
 try:
     # use mkl_fft if installed
     from mkl_fft import fft2, ifft2
 
     def convolve(mov: np.ndarray, img: np.ndarray) -> np.ndarray:
         """
-        Returns the 3D array 'mov' convolved by a 2D array 'img'.
+        Returns the 3D array "mov" convolved by a 2D array "img".
 
         Parameters
         ----------
@@ -29,17 +28,17 @@ def convolve(mov: np.ndarray, img: np.ndarray) -> np.ndarray:
         -------
         convolved_data: nImg x Ly x Lx
         """
-        return ifft2(apply_dotnorm(fft2(mov), img)) #.astype(np.complex64)
+        return ifft2(apply_dotnorm(fft2(mov), img))  #.astype(np.complex64)
 except:
     try:
         # pytorch > 1.7
-        from torch.fft import fft as torch_fft 
+        from torch.fft import fft as torch_fft
         from torch.fft import fft2 as torch_fft2
         from torch.fft import ifft as torch_ifft
         from torch.fft import ifft2 as torch_ifft2
     except:
         # pytorch <= 1.7
-        raise ImportError('pytorch version > 1.7 required')
+        raise ImportError("pytorch version > 1.7 required")
 
     eps = torch.complex(torch.tensor(1e-5), torch.tensor(0.0))
 
@@ -63,7 +62,7 @@ def ifft2(data, size=None):
 
     def convolve(mov: np.ndarray, img: np.ndarray) -> np.ndarray:
         """
-        Returns the 3D array 'mov' convolved by a 2D array 'img'.
+        Returns the 3D array "mov" convolved by a 2D array "img".
 
         Parameters
         ----------
@@ -79,24 +78,27 @@ def convolve(mov: np.ndarray, img: np.ndarray) -> np.ndarray:
         convolved_data: nImg x Ly x Lx
         """
         mov_fft = torch.from_numpy(mov)
-        mov_fft = torch_fft2(mov_fft, dim=(-2,-1))
+        mov_fft = torch_fft2(mov_fft, dim=(-2, -1))
         #mov_fft = torch_fft(torch_fft(mov_fft, dim=-1), dim=-2)
         mov_fft /= (eps + torch.abs(mov_fft))
         mov_fft *= torch.from_numpy(img)
-        mov_fft = torch.real(torch_ifft2(mov_fft, dim=(-2,-1)))
+        mov_fft = torch.real(torch_ifft2(mov_fft, dim=(-2, -1)))
         return mov_fft.numpy()
 
-@vectorize([complex64(complex64, complex64)], nopython=True, target='parallel')
+
+@vectorize([complex64(complex64, complex64)], nopython=True, target="parallel")
 def apply_dotnorm(Y, cfRefImg):
     return Y / (np.complex64(1e-5) + np.abs(Y)) * cfRefImg
 
 
-#@vectorize(['float32(int16, float32, float32)', 'float32(float32, float32, float32)'], nopython=True, target='parallel', cache=True)
+#@vectorize(["float32(int16, float32, float32)", "float32(float32, float32, float32)"], nopython=True, target="parallel", cache=True)
 #def addmultiply(x, mul, add):
 #    return np.float32(x) * mul + add
 
 
-@vectorize(['complex64(int16, float32, float32)', 'complex64(float32, float32, float32)'], nopython=True, target='parallel', cache=True)
+@vectorize(
+    ["complex64(int16, float32, float32)", "complex64(float32, float32, float32)"],
+    nopython=True, target="parallel", cache=True)
 def addmultiply(x, mul, add):
     return np.complex64(np.float32(x) * mul + add)
 
@@ -138,7 +140,7 @@ def meshgrid_mean_centered(x: int, y: int) -> Tuple[np.ndarray, np.ndarray]:
 
 
 def gaussian_fft(sig, Ly: int, Lx: int):
-    '''
+    """
     gaussian filter in the fft domain with std sig and size Ly,Lx
 
     Parameters
@@ -154,10 +156,10 @@ def gaussian_fft(sig, Ly: int, Lx: int):
     fhg: np.ndarray
         smoothing filter in Fourier domain
 
-    '''
+    """
     xx, yy = meshgrid_mean_centered(x=Lx, y=Ly)
-    hgx = np.exp(-np.square(xx/sig) / 2)
-    hgy = np.exp(-np.square(yy/sig) / 2)
+    hgx = np.exp(-np.square(xx / sig) / 2)
+    hgy = np.exp(-np.square(yy / sig) / 2)
     hgg = hgy * hgx
     hgg /= hgg.sum()
     fhg = np.real(fft2(ifftshift(hgg)))
@@ -165,7 +167,7 @@ def gaussian_fft(sig, Ly: int, Lx: int):
 
 
 def spatial_taper(sig, Ly, Lx):
-    '''
+    """
     Returns spatial taper  on edges with gaussian of std sig
 
     Parameters
@@ -181,7 +183,7 @@ def spatial_taper(sig, Ly, Lx):
     maskMul
 
 
-    '''
+    """
     xx, yy = meshgrid_mean_centered(x=Lx, y=Ly)
     mY = ((Ly - 1) / 2) - 2 * sig
     mX = ((Lx - 1) / 2) - 2 * sig
@@ -190,9 +192,10 @@ def spatial_taper(sig, Ly, Lx):
     maskMul = maskY * maskX
     return maskMul
 
+
 def temporal_smooth(data: np.ndarray, sigma: float) -> np.ndarray:
     """
-    Returns Gaussian filtered 'frames' ndarray over first dimension
+    Returns Gaussian filtered "frames" ndarray over first dimension
 
     Parameters
     ----------
@@ -229,16 +232,17 @@ def spatial_smooth(data: np.ndarray, window: int):
     if window and window % 2:
         raise ValueError("Filter window must be an even integer.")
     if data.ndim == 2:
-        data = data[np.newaxis, : ,:]
+        data = data[np.newaxis, :, :]
 
     half_pad = window // 2
-    data_padded = np.pad(data, ((0, 0), (half_pad, half_pad), (half_pad, half_pad)), mode='constant', constant_values=0)
+    data_padded = np.pad(data, ((0, 0), (half_pad, half_pad), (half_pad, half_pad)),
+                         mode="constant", constant_values=0)
 
     data_summed = data_padded.cumsum(axis=1).cumsum(axis=2, dtype=np.float32)
     data_summed = (data_summed[:, window:, :] - data_summed[:, :-window, :])  # in X
     data_summed = (data_summed[:, :, window:] - data_summed[:, :, :-window])  # in Y
-    data_summed /= window ** 2
-    
+    data_summed /= window**2
+
     return data_summed.squeeze()
 
 
@@ -260,15 +264,15 @@ def spatial_high_pass(data, N):
     """
     if data.ndim == 2:
         data = data[np.newaxis, :, :]
-    data_filtered = data - (spatial_smooth(data, N) / spatial_smooth(np.ones((1, data.shape[1], data.shape[2])), N))
+    data_filtered = data - (spatial_smooth(data, N) /
+                            spatial_smooth(np.ones(
+                                (1, data.shape[1], data.shape[2])), N))
     return data_filtered.squeeze()
 
 
-
-
 def complex_fft2(img: np.ndarray, pad_fft: bool = False) -> np.ndarray:
     """
-    Returns the complex conjugate of the fft-transformed 2D array 'img', optionally padded for speed.
+    Returns the complex conjugate of the fft-transformed 2D array "img", optionally padded for speed.
 
     Parameters
     ----------
@@ -280,12 +284,13 @@ def complex_fft2(img: np.ndarray, pad_fft: bool = False) -> np.ndarray:
 
     """
     Ly, Lx = img.shape
-    return np.conj(fft2(img, (next_fast_len(Ly), next_fast_len(Lx)))) if pad_fft else np.conj(fft2(img))
+    return np.conj(fft2(img, (next_fast_len(Ly),
+                              next_fast_len(Lx)))) if pad_fft else np.conj(fft2(img))
 
 
 def kernelD(xs: np.ndarray, ys: np.ndarray, sigL: float = 0.85) -> np.ndarray:
     """
-    Gaussian kernel from xs (1D array) to ys (1D array), with the 'sigL' smoothing width for up-sampling kernels, (best between 0.5 and 1.0)
+    Gaussian kernel from xs (1D array) to ys (1D array), with the "sigL" smoothing width for up-sampling kernels, (best between 0.5 and 1.0)
 
     Parameters
     ----------
@@ -301,7 +306,7 @@ def kernelD(xs: np.ndarray, ys: np.ndarray, sigL: float = 0.85) -> np.ndarray:
     ys0, ys1 = np.meshgrid(ys, ys)
     dxs = xs0.reshape(-1, 1) - ys0.reshape(1, -1)
     dys = xs1.reshape(-1, 1) - ys1.reshape(1, -1)
-    K = np.exp(-(dxs ** 2 + dys ** 2) / (2 * sigL ** 2))
+    K = np.exp(-(dxs**2 + dys**2) / (2 * sigL**2))
     return K
 
 
@@ -319,7 +324,7 @@ def kernelD2(xs: int, ys: int) -> np.ndarray:
     ys, xs = np.meshgrid(xs, ys)
     ys = ys.flatten().reshape(1, -1)
     xs = xs.flatten().reshape(1, -1)
-    R = np.exp(-((ys - ys.T) ** 2 + (xs - xs.T) ** 2))
+    R = np.exp(-((ys - ys.T)**2 + (xs - xs.T)**2))
     R = R / np.sum(R, axis=0)
     return R
 
@@ -344,4 +349,3 @@ def mat_upsample(lpad: int, subpixel: int = 10):
     nup = larUP.shape[0]
     Kmat = np.linalg.inv(kernelD(lar, lar)) @ kernelD(lar, larUP)
     return Kmat, nup
-
diff --git a/suite2p/registration/zalign.py b/suite2p/registration/zalign.py
index 7e78b443f..ea1e1d527 100644
--- a/suite2p/registration/zalign.py
+++ b/suite2p/registration/zalign.py
@@ -6,7 +6,8 @@
 
 from . import nonrigid, rigid, utils
 
-# This function doesn't work. Has a bunch of name errors. 
+
+# This function doesn"t work. Has a bunch of name errors.
 def register_stack(Z, ops):
     """
 
@@ -22,54 +23,62 @@ def register_stack(Z, ops):
     ops: dict
     """
 
-    if 'refImg' not in ops:
-        ops['refImg'] = Z.mean(axis=0)
-    ops['nframes'], ops['Ly'], ops['Lx'] = Z.shape
+    if "refImg" not in ops:
+        ops["refImg"] = Z.mean(axis=0)
+    ops["nframes"], ops["Ly"], ops["Lx"] = Z.shape
 
-    if ops['nonrigid']:
-        ops['yblock'], ops['xblock'], ops['nblocks'], ops['block_size'], ops['NRsm'] = nonrigid.make_blocks(
-            Ly=ops['Ly'], Lx=ops['Lx'], block_size=ops['block_size']
-        )
+    if ops["nonrigid"]:
+        ops["yblock"], ops["xblock"], ops["nblocks"], ops["block_size"], ops[
+            "NRsm"] = nonrigid.make_blocks(Ly=ops["Ly"], Lx=ops["Lx"],
+                                           block_size=ops["block_size"])
 
-    Ly = ops['Ly']
-    Lx = ops['Lx']
+    Ly = ops["Ly"]
+    Lx = ops["Lx"]
 
-    nbatch = ops['batch_size']
-    meanImg = np.zeros((Ly, Lx)) # mean of this stack
+    nbatch = ops["batch_size"]
+    meanImg = np.zeros((Ly, Lx))  # mean of this stack
 
-    yoff = np.zeros((0,),np.float32)
-    xoff = np.zeros((0,),np.float32)
-    corrXY = np.zeros((0,),np.float32)
-    if ops['nonrigid']:
-        yoff1 = np.zeros((0,nb),np.float32)
-        xoff1 = np.zeros((0,nb),np.float32)
-        corrXY1 = np.zeros((0,nb),np.float32)
+    yoff = np.zeros((0,), np.float32)
+    xoff = np.zeros((0,), np.float32)
+    corrXY = np.zeros((0,), np.float32)
+    if ops["nonrigid"]:
+        yoff1 = np.zeros((0, nb), np.float32)
+        xoff1 = np.zeros((0, nb), np.float32)
+        corrXY1 = np.zeros((0, nb), np.float32)
 
-    maskMul, maskOffset, cfRefImg = rigid.prepare_masks(refImg, ops) # prepare masks for rigid registration
-    if ops['nonrigid']:
+    maskMul, maskOffset, cfRefImg = rigid.prepare_masks(
+        refImg, ops)  # prepare masks for rigid registration
+    if ops["nonrigid"]:
         # prepare masks for non- rigid registration
         maskMulNR, maskOffsetNR, cfRefImgNR = nonrigid.prepare_masks(refImg, ops)
-        refAndMasks = [maskMul, maskOffset, cfRefImg, maskMulNR, maskOffsetNR, cfRefImgNR]
-        nb = ops['nblocks'][0] * ops['nblocks'][1]
+        refAndMasks = [
+            maskMul, maskOffset, cfRefImg, maskMulNR, maskOffsetNR, cfRefImgNR
+        ]
+        nb = ops["nblocks"][0] * ops["nblocks"][1]
     else:
         refAndMasks = [maskMul, maskOffset, cfRefImg]
 
     k = 0
     nfr = 0
-    Zreg = np.zeros((nframes, Ly, Lx,), 'int16')
+    Zreg = np.zeros((
+        nframes,
+        Ly,
+        Lx,
+    ), "int16")
     while True:
-        irange = np.arange(nfr, nfr+nbatch)
-        data = Z[irange, :,:]
-        if data.size==0:
+        irange = np.arange(nfr, nfr + nbatch)
+        data = Z[irange, :, :]
+        if data.size == 0:
             break
         data = np.reshape(data, (-1, Ly, Lx))
-        dwrite, ymax, xmax, cmax, yxnr = rigid.phasecorr(data, refAndMasks, ops) # not here
-        dwrite = dwrite.astype('int16') # need to hold on to this
+        dwrite, ymax, xmax, cmax, yxnr = rigid.phasecorr(data, refAndMasks,
+                                                         ops)  # not here
+        dwrite = dwrite.astype("int16")  # need to hold on to this
         meanImg += dwrite.sum(axis=0)
         yoff = np.hstack((yoff, ymax))
         xoff = np.hstack((xoff, xmax))
         corrXY = np.hstack((corrXY, cmax))
-        if ops['nonrigid']:
+        if ops["nonrigid"]:
             yoff1 = np.vstack((yoff1, yxnr[0]))
             xoff1 = np.vstack((xoff1, yxnr[1]))
             corrXY1 = np.vstack((corrXY1, yxnr[2]))
@@ -77,34 +86,35 @@ def register_stack(Z, ops):
         Zreg[irange] = dwrite
 
         k += 1
-        if k%5==0:
-            print('%d/%d frames %4.2f sec'%(nfr, ops['nframes'], time.time()-k0)) # where is this timer set?
+        if k % 5 == 0:
+            print("%d/%d frames %4.2f sec" %
+                  (nfr, ops["nframes"], time.time() - k0))  # where is this timer set?
 
     # compute some potentially useful info
-    ops['th_badframes'] = 100
+    ops["th_badframes"] = 100
     dx = xoff - medfilt(xoff, 101)
     dy = yoff - medfilt(yoff, 101)
     dxy = (dx**2 + dy**2)**.5
     cXY = corrXY / medfilt(corrXY, 101)
-    px = dxy/np.mean(dxy) / np.maximum(0, cXY)
-    ops['badframes'] = px > ops['th_badframes']
-    ymin = np.maximum(0, np.ceil(np.amax(yoff[np.logical_not(ops['badframes'])])))
-    ymax = ops['Ly'] + np.minimum(0, np.floor(np.amin(yoff)))
-    xmin = np.maximum(0, np.ceil(np.amax(xoff[np.logical_not(ops['badframes'])])))
-    xmax = ops['Lx'] + np.minimum(0, np.floor(np.amin(xoff)))
-    ops['yrange'] = [int(ymin), int(ymax)]
-    ops['xrange'] = [int(xmin), int(xmax)]
-    ops['corrXY'] = corrXY
-
-    ops['yoff'] = yoff
-    ops['xoff'] = xoff
-
-    if ops['nonrigid']:
-        ops['yoff1'] = yoff1
-        ops['xoff1'] = xoff1
-        ops['corrXY1'] = corrXY1
-
-    ops['meanImg'] = meanImg/ops['nframes']
+    px = dxy / np.mean(dxy) / np.maximum(0, cXY)
+    ops["badframes"] = px > ops["th_badframes"]
+    ymin = np.maximum(0, np.ceil(np.amax(yoff[np.logical_not(ops["badframes"])])))
+    ymax = ops["Ly"] + np.minimum(0, np.floor(np.amin(yoff)))
+    xmin = np.maximum(0, np.ceil(np.amax(xoff[np.logical_not(ops["badframes"])])))
+    xmax = ops["Lx"] + np.minimum(0, np.floor(np.amin(xoff)))
+    ops["yrange"] = [int(ymin), int(ymax)]
+    ops["xrange"] = [int(xmin), int(xmax)]
+    ops["corrXY"] = corrXY
+
+    ops["yoff"] = yoff
+    ops["xoff"] = xoff
+
+    if ops["nonrigid"]:
+        ops["yoff1"] = yoff1
+        ops["xoff1"] = xoff1
+        ops["corrXY1"] = corrXY1
+
+    ops["meanImg"] = meanImg / ops["nframes"]
 
     return Zreg, ops
 
@@ -119,50 +129,50 @@ def compute_zpos(Zreg, ops):
         size [nplanes x Ly x Lx], z-stack
 
     ops : dictionary
-        'reg_file' <- binary to register to z-stack, 'smooth_sigma',
-        'Ly', 'Lx', 'batch_size'
+        "reg_file" <- binary to register to z-stack, "smooth_sigma",
+        "Ly", "Lx", "batch_size"
 
     Returns
     -------
     ops_orig
     zcorr
     """
-    if 'reg_file' not in ops:
-        raise IOError('no binary specified')
+    if "reg_file" not in ops:
+        raise IOError("no binary specified")
 
-    nbatch = ops['batch_size']
-    Ly = ops['Ly']
-    Lx = ops['Lx']
+    nbatch = ops["batch_size"]
+    Ly = ops["Ly"]
+    Lx = ops["Lx"]
     nbytesread = 2 * Ly * Lx * nbatch
 
     ops_orig = ops.copy()
-    ops['nonrigid'] = False
+    ops["nonrigid"] = False
     nplanes, zLy, zLx = Zreg.shape
     if Zreg.shape[1] > Ly or Zreg.shape[2] != Lx:
-        Zreg = Zreg[:, ]
+        Zreg = Zreg[
+            :,
+        ]
 
-    nbytes = os.path.getsize(ops['reg_file'])
-    nFrames = int(nbytes/(2 * Ly * Lx))
+    nbytes = os.path.getsize(ops["reg_file"])
+    nFrames = int(nbytes / (2 * Ly * Lx))
 
-    reg_file = open(ops['reg_file'], 'rb')
+    reg_file = open(ops["reg_file"], "rb")
     refAndMasks = []
     for Z in Zreg:
-        if ops['1Preg']:
+        if ops["1Preg"]:
             Z = Z.astype(np.float32)
             Z = Z[np.newaxis, :, :]
-            if ops['pre_smooth']:
-                Z = utils.spatial_smooth(Z, int(ops['pre_smooth']))
-            Z = utils.spatial_high_pass(Z, int(ops['spatial_hp_reg']))
+            if ops["pre_smooth"]:
+                Z = utils.spatial_smooth(Z, int(ops["pre_smooth"]))
+            Z = utils.spatial_high_pass(Z, int(ops["spatial_hp_reg"]))
             Z = Z.squeeze()
 
         maskMul, maskOffset = rigid.compute_masks(
             refImg=Z,
-            maskSlope=ops['spatial_taper'] if ops['1Preg'] else 3 * ops['smooth_sigma'],
-        )
-        cfRefImag = rigid.phasecorr_reference(
-            refImg=Z,
-            smooth_sigma=ops['smooth_sigma']
+            maskSlope=ops["spatial_taper"] if ops["1Preg"] else 3 * ops["smooth_sigma"],
         )
+        cfRefImag = rigid.phasecorr_reference(refImg=Z,
+                                              smooth_sigma=ops["smooth_sigma"])
         cfRefImag = cfRefImag[np.newaxis, :, :]
         refAndMasks.append((maskMul, maskOffset, cfRefImag))
 
@@ -173,35 +183,38 @@ def compute_zpos(Zreg, ops):
     while True:
         buff = reg_file.read(nbytesread)
         data = np.frombuffer(buff, dtype=np.int16, offset=0).copy()
-        if (data.size==0) | (nfr >= ops['nframes']):
+        if (data.size == 0) | (nfr >= ops["nframes"]):
             break
         data = np.float32(np.reshape(data, (-1, Ly, Lx)))
-        inds = np.arange(nfr, nfr+data.shape[0], 1, int)
-        for z,ref in enumerate(refAndMasks):
+        inds = np.arange(nfr, nfr + data.shape[0], 1, int)
+        for z, ref in enumerate(refAndMasks):
 
             # preprocessing for 1P recordings
-            if ops['1Preg']:
+            if ops["1Preg"]:
                 data = data.astype(np.float32)
 
-                if ops['pre_smooth']:
-                    data = utils.spatial_smooth(data, int(ops['pre_smooth']))
-                data = utils.spatial_high_pass(data, int(ops['spatial_hp_reg']))
+                if ops["pre_smooth"]:
+                    data = utils.spatial_smooth(data, int(ops["pre_smooth"]))
+                data = utils.spatial_high_pass(data, int(ops["spatial_hp_reg"]))
 
             maskMul, maskOffset, cfRefImg = ref
             cfRefImg = cfRefImg.squeeze()
 
             _, _, zcorr[z, inds] = rigid.phasecorr(
-                data=rigid.apply_masks(data=data, maskMul=maskMul, maskOffset=maskOffset),
+                data=rigid.apply_masks(data=data, maskMul=maskMul,
+                                       maskOffset=maskOffset),
                 cfRefImg=cfRefImg,
-                maxregshift=ops['maxregshift'],
-                smooth_sigma_time=ops['smooth_sigma_time'],
+                maxregshift=ops["maxregshift"],
+                smooth_sigma_time=ops["smooth_sigma_time"],
             )
-            if z%10 == 1:
-                print('%d planes, %d/%d frames, %0.2f sec.'%(z, nfr, ops['nframes'], time.time()-t0))
-        print('%d planes, %d/%d frames, %0.2f sec.'%(z, nfr, ops['nframes'], time.time()-t0))
+            if z % 10 == 1:
+                print("%d planes, %d/%d frames, %0.2f sec." %
+                      (z, nfr, ops["nframes"], time.time() - t0))
+        print("%d planes, %d/%d frames, %0.2f sec." %
+              (z, nfr, ops["nframes"], time.time() - t0))
         nfr += data.shape[0]
-        k+=1
+        k += 1
 
     reg_file.close()
-    ops_orig['zcorr'] = zcorr
+    ops_orig["zcorr"] = zcorr
     return ops_orig, zcorr
diff --git a/suite2p/run_s2p.py b/suite2p/run_s2p.py
index eb4e947dd..a43e65d1c 100644
--- a/suite2p/run_s2p.py
+++ b/suite2p/run_s2p.py
@@ -5,7 +5,7 @@
 from datetime import datetime
 from getpass import getpass
 import pathlib
-
+import contextlib
 import numpy as np
 #from scipy.io import savemat
 
@@ -17,13 +17,39 @@
 except ImportError:
     HAS_HAUS = False
 
+try:
+    import pynwb
+    HAS_NWB = True
+except ImportError:
+    HAS_NWB = False
+
+try:
+    import nd2
+    HAS_ND2 = True
+except ImportError:
+    HAS_ND2 = False
+
+try:
+    import h5py
+    HAS_H5PY = True
+except ImportError:
+    HAS_H5PY = False
+
+try:
+    import sbxreader
+    HAS_SBX = True
+except ImportError:
+    HAS_SBX = False
+
 from functools import partial
 from pathlib import Path
-print = partial(print,flush=True)
 
-def pipeline(f_reg, f_raw=None, f_reg_chan2=None, f_raw_chan2=None, 
+print = partial(print, flush=True)
+
+
+def pipeline(f_reg, f_raw=None, f_reg_chan2=None, f_raw_chan2=None,
              run_registration=True, ops=default_ops(), stat=None):
-    """ run suite2p processing on array or BinaryRWFile 
+    """ run suite2p processing on array or BinaryFile 
     
     f_reg: required, registered or unregistered frames
         n_frames x Ly x Lx
@@ -45,166 +71,171 @@ def pipeline(f_reg, f_raw=None, f_reg_chan2=None, f_raw_chan2=None,
     stat: optional, input predefined masks
     
     """
-    
+
     plane_times = {}
     t1 = time.time()
-    
+
     # Select file for classification
-    ops_classfile = ops.get('classifier_path')
+    ops_classfile = ops.get("classifier_path")
     builtin_classfile = classification.builtin_classfile
     user_classfile = classification.user_classfile
     if ops_classfile:
-        print(f'NOTE: applying classifier {str(ops_classfile)}')
+        print(f"NOTE: applying classifier {str(ops_classfile)}")
         classfile = ops_classfile
-    elif ops['use_builtin_classifier'] or not user_classfile.is_file():
-        print(f'NOTE: Applying builtin classifier at {str(builtin_classfile)}')
+    elif ops["use_builtin_classifier"] or not user_classfile.is_file():
+        print(f"NOTE: Applying builtin classifier at {str(builtin_classfile)}")
         classfile = builtin_classfile
     else:
-        print(f'NOTE: applying default {str(user_classfile)}')
+        print(f"NOTE: applying default {str(user_classfile)}")
         classfile = user_classfile
 
     if run_registration:
         raw = f_raw is not None
         # if already shifted by bidiphase, do not shift again
-        if not raw and ops['do_bidiphase'] and ops['bidiphase'] != 0:
-            ops['bidi_corrected'] = True
-        
+        if not raw and ops["do_bidiphase"] and ops["bidiphase"] != 0:
+            ops["bidi_corrected"] = True
+
         ######### REGISTRATION #########
-        t11=time.time()
-        print('----------- REGISTRATION')
-        refImg = ops['refImg'] if 'refImg' in ops and ops.get('force_refImg', False) else None
-        
-        align_by_chan2 = ops['functional_chan'] != ops['align_by_chan']
-        registration_outputs = registration.register.registration_wrapper(f_reg, f_raw=f_raw, f_reg_chan2=f_reg_chan2, f_raw_chan2=f_raw_chan2, 
-                                                                            refImg=refImg, align_by_chan2=align_by_chan2, ops=ops)
-
-        ops = registration.register.save_registration_outputs_to_ops(registration_outputs, ops)
+        t11 = time.time()
+        print("----------- REGISTRATION")
+        refImg = ops["refImg"] if "refImg" in ops and ops.get("force_refImg",
+                                                              False) else None
+
+        align_by_chan2 = ops["functional_chan"] != ops["align_by_chan"]
+        registration_outputs = registration.registration_wrapper(
+            f_reg, f_raw=f_raw, f_reg_chan2=f_reg_chan2, f_raw_chan2=f_raw_chan2,
+            refImg=refImg, align_by_chan2=align_by_chan2, ops=ops)
+
+        ops = registration.save_registration_outputs_to_ops(registration_outputs, ops)
         # add enhanced mean image
-        meanImgE = registration.register.compute_enhanced_mean_image(ops['meanImg'].astype(np.float32), ops)
-        ops['meanImgE'] = meanImgE
+        meanImgE = registration.compute_enhanced_mean_image(
+            ops["meanImg"].astype(np.float32), ops)
+        ops["meanImgE"] = meanImgE
 
-        if ops.get('ops_path'):
-            np.save(ops['ops_path'], ops)
+        if ops.get("ops_path"):
+            np.save(ops["ops_path"], ops)
 
-        plane_times['registration'] = time.time()-t11
-        print('----------- Total %0.2f sec' % plane_times['registration'])
+        plane_times["registration"] = time.time() - t11
+        print("----------- Total %0.2f sec" % plane_times["registration"])
         n_frames, Ly, Lx = f_reg.shape
 
-        if ops['two_step_registration'] and ops['keep_movie_raw']:
-            print('----------- REGISTRATION STEP 2')
-            print('(making mean image (excluding bad frames)')
+        if ops["two_step_registration"] and ops["keep_movie_raw"]:
+            print("----------- REGISTRATION STEP 2")
+            print("(making mean image (excluding bad frames)")
             nsamps = min(n_frames, 1000)
-            inds = np.linspace(0, n_frames, 1+nsamps).astype(np.int64)[:-1]
+            inds = np.linspace(0, n_frames, 1 + nsamps).astype(np.int64)[:-1]
             if align_by_chan2:
                 refImg = f_reg_chan2[inds].astype(np.float32).mean(axis=0)
             else:
                 refImg = f_reg[inds].astype(np.float32).mean(axis=0)
-            registration_outputs = registration.register.registration_wrapper(f_reg, f_raw=None, f_reg_chan2=f_reg_chan2, f_raw_chan2=None, 
-                                                                                refImg=refImg, align_by_chan2=align_by_chan2, ops=ops)
-            if ops.get('ops_path'):
-                np.save(ops['ops_path'], ops)
-            plane_times['two_step_registration'] = time.time()-t11
-            print('----------- Total %0.2f sec' % plane_times['two_step_registration'])
+            registration_outputs = registration.registration_wrapper(
+                f_reg, f_raw=None, f_reg_chan2=f_reg_chan2, f_raw_chan2=None,
+                refImg=refImg, align_by_chan2=align_by_chan2, ops=ops)
+            if ops.get("ops_path"):
+                np.save(ops["ops_path"], ops)
+            plane_times["two_step_registration"] = time.time() - t11
+            print("----------- Total %0.2f sec" % plane_times["two_step_registration"])
 
         # compute metrics for registration
-        if ops.get('do_regmetrics', True) and n_frames>=1500:
+        if ops.get("do_regmetrics", True) and n_frames >= 1500:
             t0 = time.time()
             # n frames to pick from full movie
-            nsamp = min(2000 if n_frames < 5000 or Ly > 700 or Lx > 700 else 5000, n_frames)
-            inds = np.linspace(0, n_frames - 1, nsamp).astype('int')
+            nsamp = min(2000 if n_frames < 5000 or Ly > 700 or Lx > 700 else 5000,
+                        n_frames)
+            inds = np.linspace(0, n_frames - 1, nsamp).astype("int")
             mov = f_reg[inds]
-            mov = mov[:, ops['yrange'][0]:ops['yrange'][-1], ops['xrange'][0]:ops['xrange'][-1]]
+            mov = mov[:, ops["yrange"][0]:ops["yrange"][-1],
+                      ops["xrange"][0]:ops["xrange"][-1]]
             ops = registration.get_pc_metrics(mov, ops)
-            plane_times['registration_metrics'] = time.time()-t0
-            print('Registration metrics, %0.2f sec.' % plane_times['registration_metrics'])
-            if ops.get('ops_path'):
-                np.save(ops['ops_path'], ops)
-    
-    if ops.get('roidetect', True):
+            plane_times["registration_metrics"] = time.time() - t0
+            print("Registration metrics, %0.2f sec." %
+                  plane_times["registration_metrics"])
+            if ops.get("ops_path"):
+                np.save(ops["ops_path"], ops)
+
+    if ops.get("roidetect", True):
         n_frames, Ly, Lx = f_reg.shape
         ######## CELL DETECTION ##############
-        t11=time.time()
-        print('----------- ROI DETECTION')
+        t11 = time.time()
+        print("----------- ROI DETECTION")
         if stat is None:
-            ops, stat = detection.detection_wrapper(f_reg,
-                                                    ops=ops, 
-                                                    classfile=classfile)
-        plane_times['detection'] = time.time()-t11
-        print('----------- Total %0.2f sec.' % plane_times['detection'])
+            ops, stat = detection.detection_wrapper(f_reg, ops=ops, classfile=classfile)
+        plane_times["detection"] = time.time() - t11
+        print("----------- Total %0.2f sec." % plane_times["detection"])
 
-        
         if len(stat) > 0:
             ######## ROI EXTRACTION ##############
-            t11=time.time()
-            print('----------- EXTRACTION')
-            stat, F, Fneu, F_chan2, Fneu_chan2 = extraction.extraction_wrapper(stat, f_reg, f_reg_chan2=f_reg_chan2, ops=ops)
+            t11 = time.time()
+            print("----------- EXTRACTION")
+            stat, F, Fneu, F_chan2, Fneu_chan2 = extraction.extraction_wrapper(
+                stat, f_reg, f_reg_chan2=f_reg_chan2, ops=ops)
             # save results
-            if ops.get('ops_path'):
-                np.save(ops['ops_path'], ops)
+            if ops.get("ops_path"):
+                np.save(ops["ops_path"], ops)
 
-            plane_times['extraction'] = time.time()-t11
-            print('----------- Total %0.2f sec.' % plane_times['extraction'])
+            plane_times["extraction"] = time.time() - t11
+            print("----------- Total %0.2f sec." % plane_times["extraction"])
 
             ######## ROI CLASSIFICATION ##############
-            t11=time.time()
-            print('----------- CLASSIFICATION')
+            t11 = time.time()
+            print("----------- CLASSIFICATION")
             if len(stat):
                 iscell = classification.classify(stat=stat, classfile=classfile)
             else:
                 iscell = np.zeros((0, 2))
-            plane_times['classification'] = time.time()-t11
-            
+            plane_times["classification"] = time.time() - t11
+
             ######### SPIKE DECONVOLUTION ###############
-            fpath = ops['save_path']
-            if ops.get('spikedetect', True):
-                t11=time.time()
-                print('----------- SPIKE DECONVOLUTION')
-                dF = F.copy() - ops['neucoeff']*Fneu
-                dF = extraction.preprocess(
-                    F=dF,
-                    baseline=ops['baseline'],
-                    win_baseline=ops['win_baseline'],
-                    sig_baseline=ops['sig_baseline'],
-                    fs=ops['fs'],
-                    prctile_baseline=ops['prctile_baseline']
-                )
-                spks = extraction.oasis(F=dF, batch_size=ops['batch_size'], tau=ops['tau'], fs=ops['fs'])
-                plane_times['deconvolution'] = time.time()-t11
-                print('----------- Total %0.2f sec.' % plane_times['deconvolution'])
+            fpath = ops["save_path"]
+            if ops.get("spikedetect", True):
+                t11 = time.time()
+                print("----------- SPIKE DECONVOLUTION")
+                dF = F.copy() - ops["neucoeff"] * Fneu
+                dF = extraction.preprocess(F=dF, baseline=ops["baseline"],
+                                           win_baseline=ops["win_baseline"],
+                                           sig_baseline=ops["sig_baseline"],
+                                           fs=ops["fs"],
+                                           prctile_baseline=ops["prctile_baseline"])
+                spks = extraction.oasis(F=dF, batch_size=ops["batch_size"],
+                                        tau=ops["tau"], fs=ops["fs"])
+                plane_times["deconvolution"] = time.time() - t11
+                print("----------- Total %0.2f sec." % plane_times["deconvolution"])
             else:
                 print("WARNING: skipping spike detection (ops['spikedetect']=False)")
                 spks = np.zeros_like(F)
 
-            if ops.get('save_path'):
-                fpath = ops['save_path']
-                np.save(os.path.join(fpath, 'stat.npy'), stat)
-                np.save(os.path.join(fpath,'F.npy'), F)
-                np.save(os.path.join(fpath,'Fneu.npy'), Fneu)
-                np.save(os.path.join(fpath, 'iscell.npy'), iscell)
-                np.save(os.path.join(ops['save_path'], 'spks.npy'), spks)
+            if ops.get("save_path"):
+                fpath = ops["save_path"]
+                np.save(os.path.join(fpath, "stat.npy"), stat)
+                np.save(os.path.join(fpath, "F.npy"), F)
+                np.save(os.path.join(fpath, "Fneu.npy"), Fneu)
+                np.save(os.path.join(fpath, "iscell.npy"), iscell)
+                np.save(os.path.join(ops["save_path"], "spks.npy"), spks)
                 # if second channel, save F_chan2 and Fneu_chan2
-                if 'meanImg_chan2' in ops:
-                    np.save(os.path.join(fpath, 'F_chan2.npy'), F_chan2)
-                    np.save(os.path.join(fpath, 'Fneu_chan2.npy'), Fneu_chan2)
-            
+                if "meanImg_chan2" in ops:
+                    np.save(os.path.join(fpath, "F_chan2.npy"), F_chan2)
+                    np.save(os.path.join(fpath, "Fneu_chan2.npy"), Fneu_chan2)
+
             # save as matlab file
-            if ops.get('save_mat'):
-                stat = np.load(os.path.join(ops['save_path'], 'stat.npy'), allow_pickle=True)
-                iscell = np.load(os.path.join(ops['save_path'], 'iscell.npy'))
-                redcell = np.load(os.path.join(ops['save_path'], 'redcell.npy')) if ops['nchannels']==2 else []
+            if ops.get("save_mat"):
+                stat = np.load(os.path.join(ops["save_path"], "stat.npy"),
+                               allow_pickle=True)
+                iscell = np.load(os.path.join(ops["save_path"], "iscell.npy"))
+                redcell = np.load(os.path.join(
+                    ops["save_path"], "redcell.npy")) if ops["nchannels"] == 2 else []
                 io.save_mat(ops, stat, F, Fneu, spks, iscell, redcell)
         else:
-            print('no ROIs found, only ops.npy file saved')
+            print("no ROIs found, only ops.npy file saved")
     else:
         print("WARNING: skipping cell detection (ops['roidetect']=False)")
-    ops['timing'] = plane_times.copy()
-    plane_runtime = time.time()-t1
-    ops['timing']['total_plane_runtime'] = plane_runtime
-    if ops.get('ops_path'):
-        np.save(ops['ops_path'], ops)
+    ops["timing"] = plane_times.copy()
+    plane_runtime = time.time() - t1
+    ops["timing"]["total_plane_runtime"] = plane_runtime
+    if ops.get("ops_path"):
+        np.save(ops["ops_path"], ops)
+
+    return ops  #, stat, F, Fneu, F_chan2, Fneu_chan2, spks, iscell, redcell
 
-    return ops #, stat, F, Fneu, F_chan2, Fneu_chan2, spks, iscell, redcell
-    
 
 def run_plane(ops, ops_path=None, stat=None):
     """ run suite2p processing on a single binary file
@@ -212,7 +243,7 @@ def run_plane(ops, ops_path=None, stat=None):
     Parameters
     -----------
     ops : :obj:`dict` 
-        specify 'reg_file', 'nchannels', 'tau', 'fs'
+        specify "reg_file", "nchannels", "tau", "fs"
 
     ops_path: str
         absolute path to ops file (use if files were moved)
@@ -224,111 +255,119 @@ def run_plane(ops, ops_path=None, stat=None):
     --------
     ops : :obj:`dict` 
     """
-    
+
     ops = {**default_ops(), **ops}
-    ops['date_proc'] = datetime.now().astimezone()
-    
+    ops["date_proc"] = datetime.now().astimezone()
+
     # for running on server or on moved files, specify ops_path
     if ops_path is not None:
-        ops['save_path'] = os.path.split(ops_path)[0]
-        ops['ops_path'] = ops_path 
-        if len(ops['fast_disk'])==0 or ops['save_path']!=ops['fast_disk']:
-            if os.path.exists(os.path.join(ops['save_path'], 'data.bin')):
-                ops['reg_file'] = os.path.join(ops['save_path'], 'data.bin')
-                if 'reg_file_chan2' in ops:
-                    ops['reg_file_chan2'] = os.path.join(ops['save_path'], 'data_chan2.bin')    
-                if 'raw_file' in ops:
-                    ops['raw_file'] = os.path.join(ops['save_path'], 'data_raw.bin')
-                if 'raw_file_chan2' in ops:
-                    ops['raw_file_chan2'] = os.path.join(ops['save_path'], 'data_chan2_raw.bin')
+        ops["save_path"] = os.path.split(ops_path)[0]
+        ops["ops_path"] = ops_path
+        if len(ops["fast_disk"]) == 0 or ops["save_path"] != ops["fast_disk"]:
+            if os.path.exists(os.path.join(ops["save_path"], "data.bin")):
+                ops["reg_file"] = os.path.join(ops["save_path"], "data.bin")
+                if "reg_file_chan2" in ops:
+                    ops["reg_file_chan2"] = os.path.join(ops["save_path"],
+                                                         "data_chan2.bin")
+                if "raw_file" in ops:
+                    ops["raw_file"] = os.path.join(ops["save_path"], "data_raw.bin")
+                if "raw_file_chan2" in ops:
+                    ops["raw_file_chan2"] = os.path.join(ops["save_path"],
+                                                         "data_chan2_raw.bin")
 
     # check that there are sufficient numbers of frames
-    if ops['nframes'] < 50:
-        raise ValueError('the total number of frames should be at least 50.')
-    if ops['nframes'] < 200:
-        print('WARNING: number of frames is below 200, unpredictable behaviors may occur.')
+    if ops["nframes"] < 50:
+        raise ValueError("the total number of frames should be at least 50.")
+    if ops["nframes"] < 200:
+        print(
+            "WARNING: number of frames is below 200, unpredictable behaviors may occur."
+        )
 
     # check if registration should be done
-    if ops['do_registration']>0:
-        if 'refImg' not in ops or 'yoff' not in ops or ops['do_registration'] > 1:
-            print("NOTE: not registered / registration forced with ops['do_registration']>1")
+    if ops["do_registration"] > 0:
+        if "refImg" not in ops or "yoff" not in ops or ops["do_registration"] > 1:
+            print(
+                "NOTE: not registered / registration forced with ops['do_registration']>1"
+            )
             try:
-                del ops['yoff'], ops['xoff'], ops['corrXY']  # delete previous offsets
+                del ops["yoff"], ops["xoff"], ops["corrXY"]  # delete previous offsets
             except KeyError:
-                print('      (no previous offsets to delete)')
+                print("      (no previous offsets to delete)")
             run_registration = True
         else:
             print("NOTE: not running registration, plane already registered")
-            print('binary path: %s'%ops['reg_file'])
+            print("binary path: %s" % ops["reg_file"])
             run_registration = False
     else:
         print("NOTE: not running registration, ops['do_registration']=0")
-        print('binary path: %s'%ops['reg_file'])
+        print("binary path: %s" % ops["reg_file"])
         run_registration = False
 
-    Ly, Lx = ops['Ly'], ops['Lx']
-    
     # get binary file paths
-    raw = ops.get('keep_movie_raw') and 'raw_file' in ops and os.path.isfile(ops['raw_file'])
-    reg_file = ops['reg_file']
-    raw_file = ops.get('raw_file', 0) if raw else reg_file
-    if ops['nchannels'] > 1:
-        reg_file_chan2 = ops['reg_file_chan2']
-        raw_file_chan2 = ops.get('raw_file_chan2', 0) if raw else reg_file_chan2
+    raw = ops.get("keep_movie_raw") and "raw_file" in ops and os.path.isfile(
+        ops["raw_file"])
+    reg_file = ops["reg_file"]
+    raw_file = ops.get("raw_file", 0) if raw else reg_file
+    # get number of frames in binary file to use to initialize files if needed
+    if ops["nchannels"] > 1:
+        reg_file_chan2 = ops["reg_file_chan2"]
+        raw_file_chan2 = ops.get("raw_file_chan2", 0) if raw else reg_file_chan2
     else:
-        reg_file_chan2 = reg_file 
-        raw_file_chan2 = reg_file   
-        
-
-    with io.BinaryRWFile(Ly=Ly, Lx=Lx, filename=raw_file if raw else reg_file) as f_raw, \
-         io.BinaryRWFile(Ly=Ly, Lx=Lx, filename=reg_file) as f_reg, \
-         io.BinaryRWFile(Ly=Ly, Lx=Lx, filename=raw_file_chan2 if raw else reg_file_chan2) as f_raw_chan2,\
-         io.BinaryRWFile(Ly=Ly, Lx=Lx, filename=reg_file_chan2) as f_reg_chan2:         
-        if not raw:
-            f_raw.close()
-            f_raw = None
-            f_raw_chan2.close()
-            f_raw_chan2 = None
-        if ops['nchannels'] == 1:
-            f_reg_chan2.close() 
-            f_reg_chan2 = None
-
-        ops = pipeline(f_reg, f_raw, f_reg_chan2, f_raw_chan2, run_registration, ops, stat=stat)
-        
-    if ops.get('move_bin') and ops['save_path'] != ops['fast_disk']:
-        print('moving binary files to save_path')
-        shutil.move(ops['reg_file'], os.path.join(ops['save_path'], 'data.bin'))
-        if ops['nchannels']>1:
-            shutil.move(ops['reg_file_chan2'], os.path.join(ops['save_path'], 'data_chan2.bin'))
-        if 'raw_file' in ops:
-            shutil.move(ops['raw_file'], os.path.join(ops['save_path'], 'data_raw.bin'))
-            if ops['nchannels'] > 1:
-                shutil.move(ops['raw_file_chan2'], os.path.join(ops['save_path'], 'data_chan2_raw.bin'))
-    elif ops.get('delete_bin'):
-        print('deleting binary files')
-        os.remove(ops['reg_file'])
-        if ops['nchannels'] > 1:
-            os.remove(ops['reg_file_chan2'])
-        if 'raw_file' in ops:
-            os.remove(ops['raw_file'])
-            if ops['nchannels'] > 1:
-                os.remove(ops['raw_file_chan2'])
+        reg_file_chan2 = reg_file
+        raw_file_chan2 = reg_file
+
+    # shape of binary files
+    n_frames, Ly, Lx = ops["nframes"], ops["Ly"], ops["Lx"]
+
+    null = contextlib.nullcontext()
+    twoc = ops["nchannels"] > 1
+    with io.BinaryFile(Ly=Ly, Lx=Lx, filename=raw_file, n_frames=n_frames) \
+            if raw else null as f_raw, \
+         io.BinaryFile(Ly=Ly, Lx=Lx, filename=reg_file, n_frames=n_frames) as f_reg, \
+         io.BinaryFile(Ly=Ly, Lx=Lx, filename=raw_file_chan2, n_frames=n_frames) \
+            if raw and twoc else null as f_raw_chan2,\
+         io.BinaryFile(Ly=Ly, Lx=Lx, filename=reg_file_chan2, n_frames=n_frames) \
+            if twoc else null as f_reg_chan2:
+
+        ops = pipeline(f_reg, f_raw, f_reg_chan2, f_raw_chan2, run_registration, ops,
+                       stat=stat)
+
+    if ops.get("move_bin") and ops["save_path"] != ops["fast_disk"]:
+        print("moving binary files to save_path")
+        shutil.move(ops["reg_file"], os.path.join(ops["save_path"], "data.bin"))
+        if ops["nchannels"] > 1:
+            shutil.move(ops["reg_file_chan2"],
+                        os.path.join(ops["save_path"], "data_chan2.bin"))
+        if "raw_file" in ops:
+            shutil.move(ops["raw_file"], os.path.join(ops["save_path"], "data_raw.bin"))
+            if ops["nchannels"] > 1:
+                shutil.move(ops["raw_file_chan2"],
+                            os.path.join(ops["save_path"], "data_chan2_raw.bin"))
+    elif ops.get("delete_bin"):
+        print("deleting binary files")
+        os.remove(ops["reg_file"])
+        if ops["nchannels"] > 1:
+            os.remove(ops["reg_file_chan2"])
+        if "raw_file" in ops:
+            os.remove(ops["raw_file"])
+            if ops["nchannels"] > 1:
+                os.remove(ops["raw_file_chan2"])
     return ops
 
 
 def run_s2p(ops={}, db={}, server={}):
     """ run suite2p pipeline
 
-        need to provide a 'data_path' or 'h5py'+'h5py_key' in db or ops
+        need to provide a "data_path" or "h5py"+"h5py_key" in db or ops
 
         Parameters
         ----------
         ops : :obj:`dict`
-            specify 'nplanes', 'nchannels', 'tau', 'fs'
+            specify "nplanes", "nchannels", "tau", "fs"
         db : :obj:`dict`
-            specify 'data_path' or 'h5py'+'h5py_key' here or in ops
+            specify "data_path" or "h5py"+"h5py_key" here or in ops
         server : :obj:`dict`
-            specify 'host', 'username', 'password', 'server_root', 'local_root', 'n_cores' ( for multiplane_parallel )
+            specify "host", "username", "password", "server_root", "local_root", "n_cores" ( for multiplane_parallel )
 
 
         Returns
@@ -339,36 +378,45 @@ def run_s2p(ops={}, db={}, server={}):
     """
     t0 = time.time()
     ops = {**default_ops(), **ops, **db}
-    if isinstance(ops['diameter'], list) and len(ops['diameter'])>1 and ops['aspect']==1.0:
-        ops['aspect'] = ops['diameter'][0] / ops['diameter'][1]
+    if isinstance(ops["diameter"], list) and len(
+            ops["diameter"]) > 1 and ops["aspect"] == 1.0:
+        ops["aspect"] = ops["diameter"][0] / ops["diameter"][1]
     print(db)
-    if 'save_path0' not in ops or len(ops['save_path0'])==0:
-        if ops.get('h5py'):
-            ops['save_path0'] = os.path.split(ops['h5py'][0])[0] # Use first element in h5py key to find save_path
-        elif ops.get('nwb_file'):
-            ops['save_path0'] = os.path.split(ops['nwb_file'])[0]
+    if "save_path0" not in ops or len(ops["save_path0"]) == 0:
+        if ops.get("h5py"):
+            ops["save_path0"] = os.path.split(
+                ops["h5py"][0])[0]  # Use first element in h5py key to find save_path
+        elif ops.get("nwb_file"):
+            ops["save_path0"] = os.path.split(ops["nwb_file"])[0]
         else:
-            ops['save_path0'] = ops['data_path'][0]
-    
+            ops["save_path0"] = ops["data_path"][0]
+
     # check if there are binaries already made
-    if 'save_folder' not in ops or len(ops['save_folder'])==0:
-        ops['save_folder'] = 'suite2p'
-    save_folder = os.path.join(ops['save_path0'], ops['save_folder'])
+    if "save_folder" not in ops or len(ops["save_folder"]) == 0:
+        ops["save_folder"] = "suite2p"
+    save_folder = os.path.join(ops["save_path0"], ops["save_folder"])
     os.makedirs(save_folder, exist_ok=True)
-    plane_folders = natsorted([ f.path for f in os.scandir(save_folder) if f.is_dir() and f.name[:5]=='plane'])
+    plane_folders = natsorted([
+        f.path for f in os.scandir(save_folder) if f.is_dir() and f.name[:5] == "plane"
+    ])
     if len(plane_folders) > 0:
-        ops_paths = [os.path.join(f, 'ops.npy') for f in plane_folders]
+        ops_paths = [os.path.join(f, "ops.npy") for f in plane_folders]
         ops_found_flag = all([os.path.isfile(ops_path) for ops_path in ops_paths])
-        binaries_found_flag = all([os.path.isfile(os.path.join(f, 'data_raw.bin')) or os.path.isfile(os.path.join(f, 'data.bin')) 
-                                    for f in plane_folders])
+        binaries_found_flag = all([
+            os.path.isfile(os.path.join(f, "data_raw.bin")) or
+            os.path.isfile(os.path.join(f, "data.bin")) for f in plane_folders
+        ])
         files_found_flag = ops_found_flag and binaries_found_flag
     else:
         files_found_flag = False
-    
+
     if files_found_flag:
-        print(f'FOUND BINARIES AND OPS IN {ops_paths}')
-        print('removing previous detection and extraction files, if present')
-        files_to_remove = ['stat.npy', 'F.npy', 'Fneu.npy', 'F_chan2.npy', 'Fneu_chan2.npy', 'iscell.npy', 'redcell.npy']
+        print(f"FOUND BINARIES AND OPS IN {ops_paths}")
+        print("removing previous detection and extraction files, if present")
+        files_to_remove = [
+            "stat.npy", "F.npy", "Fneu.npy", "F_chan2.npy", "Fneu_chan2.npy",
+            "iscell.npy", "redcell.npy"
+        ]
         for p in ops_paths:
             plane_folder = os.path.split(p)[0]
             for f in files_to_remove:
@@ -376,88 +424,111 @@ def run_s2p(ops={}, db={}, server={}):
                     os.remove(os.path.join(plane_folder, f))
     # if not set up files and copy tiffs/h5py to binary
     else:
-        if len(ops['h5py']):
-            ops['input_format'] = 'h5'
-            # Overwrite data_path with path provided by h5py. 
+        if len(ops["h5py"]):
+            ops["input_format"] = "h5"
+            if not HAS_H5PY:
+                raise ImportError("h5py not found; pip install h5py")
+            # Overwrite data_path with path provided by h5py.
             # Use the directory containing the first h5 file
-            ops['data_path'] = [os.path.split(ops['h5py'][0])[0]]
-        elif len(ops['nwb_file']):
-            ops['input_format'] = 'nwb'
-        elif ops.get('mesoscan'):
-            ops['input_format'] = 'mesoscan'
-        elif ops.get('nd2'):
-            ops['input_format'] = 'nd2'
+            ops["data_path"] = [os.path.split(ops["h5py"][0])[0]]
+        elif len(ops["nwb_file"]):
+            ops["input_format"] = "nwb"
+            if not HAS_NWB:
+                raise ImportError("nwb not found; pip install pynwb")
+        elif ops.get("mesoscan"):
+            ops["input_format"] = "mesoscan"
+        elif ops.get("nd2"):
+            ops["input_format"] = "nd2"
+            if not HAS_ND2:
+                raise ImportError("nd2 not found; pip install nd2")
         elif HAS_HAUS:
-            ops['input_format'] = 'haus'
-        elif not 'input_format' in ops:
-            ops['input_format'] = 'tif'
-
+            ops["input_format"] = "haus"
+        elif not "input_format" in ops:
+            ops["input_format"] = "tif"
 
         # copy file format to a binary file
         convert_funs = {
-            'h5': io.h5py_to_binary,
-            'nwb': io.nwb_to_binary,
-            'sbx': io.sbx_to_binary,
-            'nd2': io.nd2_to_binary,
-            'mesoscan': io.mesoscan_to_binary,
-            'haus': lambda ops: haussio.load_haussio(ops['data_path'][0]).tosuite2p(ops.copy()),
-            'bruker': io.ome_to_binary,
+            "h5":
+                io.h5py_to_binary,
+            "nwb":
+                io.nwb_to_binary,
+            "sbx":
+                io.sbx_to_binary,
+            "nd2":
+                io.nd2_to_binary,
+            "mesoscan":
+                io.mesoscan_to_binary,
+            "haus":
+                lambda ops: haussio.load_haussio(ops["data_path"][0]).tosuite2p(ops.
+                                                                                copy()),
+            "bruker":
+                io.ome_to_binary,
         }
-        if ops['input_format'] in convert_funs:
-            ops0 = convert_funs[ops['input_format']](ops.copy())
+        if ops["input_format"] in convert_funs:
+            ops0 = convert_funs[ops["input_format"]](ops.copy())
             if isinstance(ops, list):
                 ops0 = ops0[0]
         else:
             ops0 = io.tiff_to_binary(ops.copy())
-        plane_folders = natsorted([ f.path for f in os.scandir(save_folder) if f.is_dir() and f.name[:5]=='plane'])
-        ops_paths = [os.path.join(f, 'ops.npy') for f in plane_folders]
-        print('time {:0.2f} sec. Wrote {} frames per binary for {} planes'.format(
-                  time.time() - t0, ops0['nframes'], len(plane_folders)
-            ))
 
-    if ops.get('multiplane_parallel'):
+        plane_folders = natsorted([
+            f.path
+            for f in os.scandir(save_folder)
+            if f.is_dir() and f.name[:5] == "plane"
+        ])
+        ops_paths = [os.path.join(f, "ops.npy") for f in plane_folders]
+        print("time {:0.2f} sec. Wrote {} frames per binary for {} planes".format(
+            time.time() - t0, ops0["nframes"], len(plane_folders)))
+
+    if ops.get("multiplane_parallel"):
         if server:
-            if 'fnc' in server.keys():
+            if "fnc" in server.keys():
                 # Call custom function.
-                server['fnc'](save_folder, server)
+                server["fnc"](save_folder, server)
             else:
                 # if user puts in server settings
-                io.server.send_jobs(save_folder, host=server['host'], username=server['username'],
-                                    password=server['password'], server_root=server['server_root'],
-                                    local_root=server['local_root'], n_cores=server['n_cores'])
+                io.server.send_jobs(save_folder, host=server["host"],
+                                    username=server["username"],
+                                    password=server["password"],
+                                    server_root=server["server_root"],
+                                    local_root=server["local_root"],
+                                    n_cores=server["n_cores"])
         else:
             # otherwise use settings modified in io/server.py
             io.server.send_jobs(save_folder)
         return None
     else:
         for ipl, ops_path in enumerate(ops_paths):
-            if ipl in ops['ignore_flyback']:
-                print('>>>> skipping flyback PLANE', ipl)
+            if ipl in ops["ignore_flyback"]:
+                print(">>>> skipping flyback PLANE", ipl)
                 continue
             op = np.load(ops_path, allow_pickle=True).item()
-            
+
             # make sure yrange and xrange are not overwritten
             for key in default_ops().keys():
-                if key not in ['data_path', 'save_path0', 'fast_disk', 'save_folder', 'subfolders']:
+                if key not in [
+                        "data_path", "save_path0", "fast_disk", "save_folder",
+                        "subfolders"
+                ]:
                     if key in ops:
                         op[key] = ops[key]
-            
-            print('>>>>>>>>>>>>>>>>>>>>> PLANE %d <<<<<<<<<<<<<<<<<<<<<<'%ipl)
+
+            print(">>>>>>>>>>>>>>>>>>>>> PLANE %d <<<<<<<<<<<<<<<<<<<<<<" % ipl)
             op = run_plane(op, ops_path=ops_path)
-            print('Plane %d processed in %0.2f sec (can open in GUI).' % 
-                    (ipl, op['timing']['total_plane_runtime']))  
-        run_time = time.time()-t0
-        print('total = %0.2f sec.' % run_time)
+            print("Plane %d processed in %0.2f sec (can open in GUI)." %
+                  (ipl, op["timing"]["total_plane_runtime"]))
+        run_time = time.time() - t0
+        print("total = %0.2f sec." % run_time)
 
         #### COMBINE PLANES or FIELDS OF VIEW ####
-        if len(ops_paths)>1 and ops['combined'] and ops.get('roidetect', True):
-            print('Creating combined view')
+        if len(ops_paths) > 1 and ops["combined"] and ops.get("roidetect", True):
+            print("Creating combined view")
             io.combined(save_folder, save=True)
-        
+
         # save to NWB
-        if ops.get('save_NWB'):
-            print('Saving in nwb format')
+        if ops.get("save_NWB"):
+            print("Saving in nwb format")
             io.save_nwb(save_folder)
 
-        print('TOTAL RUNTIME %0.2f sec' % (time.time()-t0))
+        print("TOTAL RUNTIME %0.2f sec" % (time.time() - t0))
         return op
diff --git a/suite2p/version.py b/suite2p/version.py
index 18dd684a2..19d6f2a25 100644
--- a/suite2p/version.py
+++ b/suite2p/version.py
@@ -1,4 +1,3 @@
 from importlib_metadata import metadata as _metadata
 
-
-version = _metadata('suite2p')['version']
+version = _metadata("suite2p")["version"]


Test patch:
diff --git a/.github/workflows/test_and_deploy.yml b/.github/workflows/test_and_deploy.yml
index 8a58010c3..44de9f284 100644
--- a/.github/workflows/test_and_deploy.yml
+++ b/.github/workflows/test_and_deploy.yml
@@ -22,7 +22,7 @@ jobs:
       fail-fast: false
       matrix:
         platform: [ubuntu-latest, windows-latest, macos-latest]
-        python-version: [3.8]
+        python-version: [3.8, 3.9]
 
     steps:
       - uses: actions/checkout@v2
diff --git a/tests/regression/test_registration_pipeline.py b/tests/regression/test_registration_pipeline.py
index b02320641..4bf517aef 100644
--- a/tests/regression/test_registration_pipeline.py
+++ b/tests/regression/test_registration_pipeline.py
@@ -5,7 +5,9 @@
 import numpy as np
 from pathlib import Path
 from tifffile import imread
-from suite2p.registration import register_binary
+import contextlib
+import os
+from suite2p import registration, io #import register_binary
 
 
 def prepare_for_registration(op, input_file_name, dimensions):
@@ -54,7 +56,32 @@ def check_registration_output(op, dimensions, input_path, reg_output_path_list,
     reg_ops = []
     npl = op['nplanes']
     for i in range(npl):
-        curr_op = register_binary(ops[i])
+        #curr_op = register_binary(ops[i])
+        raw = ops[i].get("keep_movie_raw") and "raw_file" in ops[i] and os.path.isfile(
+            ops[i]["raw_file"])
+        reg_file = ops[i]["reg_file"]
+        raw_file = ops[i].get("raw_file", 0) if raw else reg_file
+        if ops[i]["nchannels"] > 1:
+            reg_file_chan2 = ops[i]["reg_file_chan2"]
+            raw_file_chan2 = ops[i].get("raw_file_chan2",
+                                    0) if raw else reg_file_chan2
+        else:
+            reg_file_chan2 = reg_file
+            raw_file_chan2 = reg_file
+        null = contextlib.nullcontext()
+        twoc = ops[i]["nchannels"] > 1
+        raw_file = ops[i]["raw_file"]
+        Ly, Lx = ops[i]["Ly"], ops[i]["Lx"]
+        with io.BinaryFile(Ly=Ly, Lx=Lx, filename=raw_file) if raw else null as f_raw, \
+            io.BinaryFile(Ly=Ly, Lx=Lx, filename=reg_file) as f_reg, \
+            io.BinaryFile(Ly=Ly, Lx=Lx, filename=raw_file_chan2) if raw and twoc else null as f_raw_chan2,\
+            io.BinaryFile(Ly=Ly, Lx=Lx, filename=reg_file_chan2) if twoc else null as f_reg_chan2:
+            
+            registration_outputs = registration.register.registration_wrapper(
+                f_reg, f_raw=f_raw, f_reg_chan2=f_reg_chan2,
+                f_raw_chan2=f_raw_chan2, ops=ops[i])
+            curr_op = registration.register.save_registration_outputs_to_ops(
+                registration_outputs, ops[i])
         registered_data = imread(reg_output_path_list[i*npl])
         output_check = imread(output_path_list[i*npl])
         assert np.array_equal(registered_data, output_check)
diff --git a/tests/test_io.py b/tests/test_io.py
index afde72acc..7b5dd595d 100644
--- a/tests/test_io.py
+++ b/tests/test_io.py
@@ -21,7 +21,7 @@ def binfile1500(test_ops):
     op = io.tiff_to_binary(test_ops)
     bin_filename = str(Path(op["save_path0"]).joinpath("suite2p/plane0/data.bin"))
     with io.BinaryFile(
-        Ly=op["Ly"], Lx=op["Lx"], read_filename=bin_filename
+        Ly=op["Ly"], Lx=op["Lx"], filename=bin_filename
     ) as bin_file:
         yield bin_file
 
@@ -35,7 +35,7 @@ def replace_ops_save_path_with_local_path(request):
 
     # Workaround to load pickled NPY files on Windows containing
     # `PosixPath` objects
-    if platform.system() == 'Windows':
+    if platform.system() == "Windows":
         pathlib.PosixPath = pathlib.WindowsPath
 
     # Get the `data_folder` variable from the running test name    
@@ -93,7 +93,7 @@ def test_h5_to_binary_produces_nonnegative_output_data(test_ops):
     test_ops["data_path"] = []
     op = io.h5py_to_binary(test_ops)
     output_data = io.BinaryFile(
-        read_filename=Path(op["save_path0"], "suite2p/plane0/data.bin"),
+        filename=Path(op["save_path0"], "suite2p/plane0/data.bin"),
         Ly=op["Ly"],
         Lx=op["Lx"],
     ).data