From b1517a4755f9b9bf2c6209f0b0df4739f4a8b61a Mon Sep 17 00:00:00 2001
From: Harry Carey <harry.carey95@gmail.com>
Date: Fri, 13 Oct 2023 15:48:39 +0200
Subject: [PATCH] black reformatting

---
 PyNutil/coordinate_extraction.py             |  75 +++---
 PyNutil/counting_and_load.py                 |  59 +++--
 PyNutil/generate_target_slice.py             |   8 +-
 PyNutil/load_workflow.py                     |  14 +-
 PyNutil/main.py                              |  67 +++---
 PyNutil/propagation.py                       | 231 ++++++++++---------
 PyNutil/read_and_write.py                    |  50 ++--
 PyNutil/reconstruct_dzi.py                   |  15 +-
 PyNutil/visualign_deformations.py            |  14 +-
 messing_around_files/pyflat.py               |  40 ++--
 messing_around_files/testing_openflatfile.py |  10 +-
 scripts/create_test_data.py                  |  29 ++-
 testOOP.py                                   |   4 +-
 13 files changed, 353 insertions(+), 263 deletions(-)

diff --git a/PyNutil/coordinate_extraction.py b/PyNutil/coordinate_extraction.py
index 6079f2c..157bdc6 100644
--- a/PyNutil/coordinate_extraction.py
+++ b/PyNutil/coordinate_extraction.py
@@ -9,7 +9,7 @@ from tqdm import tqdm
 import cv2
 from skimage import measure
 import threading
-import re 
+import re
 from .reconstruct_dzi import reconstruct_dzi
 
 
@@ -42,6 +42,7 @@ def number_sections(filenames, legacy=False):
         raise ValueError("No section numbers found in filenames")
     return section_numbers
 
+
 # related to coordinate_extraction
 def get_centroids_and_area(segmentation, pixel_cut_off=0):
     """This function returns the center coordinate of each object in the segmentation.
@@ -122,7 +123,7 @@ def folder_to_atlas_space(
     method="all",
     object_cutoff=0,
     atlas_volume=None,
-    use_flat = False,
+    use_flat=False,
 ):
     """Apply Segmentation to atlas space to all segmentations in a folder."""
     """Return pixel_points, centroids, points_len, centroids_len, segmentation_filenames, """
@@ -144,29 +145,30 @@ def folder_to_atlas_space(
         flat_files = [
             file
             for file in glob(folder + "/flat_files/*")
-            if any([file.endswith('.flat'), file.endswith('.seg')])
+            if any([file.endswith(".flat"), file.endswith(".seg")])
         ]
         print(f"Found {len(flat_files)} flat files in folder {folder}")
         flat_file_nrs = [int(number_sections([ff])[0]) for ff in flat_files]
 
-        
     # Order segmentations and section_numbers
     # segmentations = [x for _,x in sorted(zip(section_numbers,segmentations))]
     # section_numbers.sort()
     points_list = [np.array([])] * len(segmentations)
     centroids_list = [np.array([])] * len(segmentations)
     region_areas_list = [
-        pd.DataFrame({
-            "idx": [],
-            "name": [],
-            "r": [],
-            "g": [],
-            "b": [],
-            "region_area": [],
-            "pixel_count": [],
-            "object_count": [],
-            "area_fraction": []
-        })
+        pd.DataFrame(
+            {
+                "idx": [],
+                "name": [],
+                "r": [],
+                "g": [],
+                "b": [],
+                "region_area": [],
+                "pixel_count": [],
+                "object_count": [],
+                "area_fraction": [],
+            }
+        )
     ] * len(segmentations)
     threads = []
     for segmentation_path, index in zip(segmentations, range(len(segmentations))):
@@ -186,7 +188,7 @@ def folder_to_atlas_space(
             args=(
                 current_slice,
                 segmentation_path,
-                atlas_labels, 
+                atlas_labels,
                 current_flat,
                 pixel_id,
                 non_linear,
@@ -197,7 +199,7 @@ def folder_to_atlas_space(
                 method,
                 object_cutoff,
                 atlas_volume,
-                use_flat
+                use_flat,
             ),
         )
         threads.append(x)
@@ -207,14 +209,14 @@ def folder_to_atlas_space(
     # Wait for threads to finish
     [t.join() for t in threads]
     # Flatten points_list
-    
 
     points_len = [len(points) if points is not None else 0 for points in points_list]
-    centroids_len = [len(centroids) if centroids is not None else 0 for centroids in centroids_list]
+    centroids_len = [
+        len(centroids) if centroids is not None else 0 for centroids in centroids_list
+    ]
     points = np.concatenate(points_list)
     centroids = np.concatenate(centroids_list)
 
-
     return (
         np.array(points),
         np.array(centroids),
@@ -228,19 +230,18 @@ def folder_to_atlas_space(
 def segmentation_to_atlas_space(
     slice,
     segmentation_path,
-    atlas_labels, 
+    atlas_labels,
     flat_file_atlas=None,
     pixel_id="auto",
     non_linear=True,
     points_list=None,
     centroids_list=None,
-    region_areas_list=None, 
+    region_areas_list=None,
     index=None,
     method="per_pixel",
     object_cutoff=0,
     atlas_volume=None,
-    use_flat=False
-    
+    use_flat=False,
 ):
     """Combines many functions to convert a segmentation to atlas space. It takes care
     of deformations."""
@@ -261,7 +262,7 @@ def segmentation_to_atlas_space(
         # Currently only works for a single label
         print("length of non background pixels: ", len(segmentation_no_background))
         pixel_id = segmentation_no_background[0]
-        print('detected pixel_id: ', pixel_id)
+        print("detected pixel_id: ", pixel_id)
 
     # Transform pixels to registration space (the registered image and segmentation have different dimensions)
     seg_height = segmentation.shape[0]
@@ -269,9 +270,17 @@ def segmentation_to_atlas_space(
     reg_height = slice["height"]
     reg_width = slice["width"]
     if use_flat == True:
-        region_areas = flat_to_dataframe(atlas_labels, flat_file_atlas, (seg_width,seg_height))
+        region_areas = flat_to_dataframe(
+            atlas_labels, flat_file_atlas, (seg_width, seg_height)
+        )
     else:
-        region_areas = flat_to_dataframe(atlas_labels, flat_file_atlas, (seg_width,seg_height), slice["anchoring"], atlas_volume)
+        region_areas = flat_to_dataframe(
+            atlas_labels,
+            flat_file_atlas,
+            (seg_width, seg_height),
+            slice["anchoring"],
+            atlas_volume,
+        )
     # This calculates reg/seg
     y_scale, x_scale = transform_to_registration(
         seg_height, seg_width, reg_height, reg_width
@@ -287,7 +296,6 @@ def segmentation_to_atlas_space(
 
     if non_linear:
         if "markers" in slice:
-            
             # This creates a triangulation using the reg width
             triangulation = triangulate(reg_width, reg_height, slice["markers"])
             if method in ["per_pixel", "all"]:
@@ -301,7 +309,10 @@ def segmentation_to_atlas_space(
                         triangulation, scaled_centroidsX, scaled_centroidsY
                     )
                 else:
-                    centroids_new_x, centroids_new_y = scaled_centroidsX, scaled_centroidsY
+                    centroids_new_x, centroids_new_y = (
+                        scaled_centroidsX,
+                        scaled_centroidsY,
+                    )
         else:
             print(
                 f"No markers found for {slice['filename']}, result for section will be linear."
@@ -326,7 +337,11 @@ def segmentation_to_atlas_space(
     if method in ["per_object", "all"]:
         if centroids_new_x is not None:
             centroids = transform_to_atlas_space(
-                slice["anchoring"], centroids_new_y, centroids_new_x, reg_height, reg_width
+                slice["anchoring"],
+                centroids_new_y,
+                centroids_new_x,
+                reg_height,
+                reg_width,
             )
         else:
             centroids = np.array([])
diff --git a/PyNutil/counting_and_load.py b/PyNutil/counting_and_load.py
index 9dce6ec..9da941f 100644
--- a/PyNutil/counting_and_load.py
+++ b/PyNutil/counting_and_load.py
@@ -89,7 +89,7 @@ def pixel_count_per_region(
     # Find colours corresponding to each region ID and add to the pandas dataframe
 
     # Look up name, r, g, b in df_allen_colours in df_counts_per_label based on "idx"
-    #Sharon, remove this here
+    # Sharon, remove this here
     new_rows = []
     for index, row in df_counts_per_label.iterrows():
         mask = df_label_colours["idx"] == row["idx"]
@@ -106,12 +106,14 @@ def pixel_count_per_region(
 
         new_rows.append(row)
 
-    df_counts_per_label_name = pd.DataFrame(new_rows, columns=["idx", "name", "pixel_count", "object_count", "r", "g", "b"])
-    #Task for Sharon:
-    #If you can get the areas per region from the flat file here 
-    #you can then use those areas to calculate the load per region here
+    df_counts_per_label_name = pd.DataFrame(
+        new_rows, columns=["idx", "name", "pixel_count", "object_count", "r", "g", "b"]
+    )
+    # Task for Sharon:
+    # If you can get the areas per region from the flat file here
+    # you can then use those areas to calculate the load per region here
     # and add to dataframe
-    #see messing around pyflat.py
+    # see messing around pyflat.py
 
     return df_counts_per_label_name
 
@@ -123,6 +125,7 @@ import cv2
 import numpy as np
 import pandas as pd
 
+
 def read_flat_file(file):
     with open(file, "rb") as f:
         b, w, h = struct.unpack(">BII", f.read(9))
@@ -134,51 +137,61 @@ def read_flat_file(file):
             image[y, x] = image_data[x + y * w]
     return image
 
+
 def read_seg_file(file):
-    with open(file,"rb") as f:
+    with open(file, "rb") as f:
+
         def byte():
             return f.read(1)[0]
+
         def code():
-            c=byte()
-            if(c<0):
+            c = byte()
+            if c < 0:
                 raise "!"
-            return c if c<128 else (c&127)|(code()<<7)
+            return c if c < 128 else (c & 127) | (code() << 7)
+
         if "SegRLEv1" != f.read(8).decode():
             raise "Header mismatch"
-        atlas=f.read(code()).decode()
+        atlas = f.read(code()).decode()
         print(f"Target atlas: {atlas}")
-        codes=[code() for x in range(code())]
-        w=code()
-        h=code()
-        data=[]
-        while len(data)<w*h:
-            data += [codes[byte() if len(codes)<=256 else code()]]*(code()+1)
+        codes = [code() for x in range(code())]
+        w = code()
+        h = code()
+        data = []
+        while len(data) < w * h:
+            data += [codes[byte() if len(codes) <= 256 else code()]] * (code() + 1)
     image_data = np.array(data)
     image = np.reshape(image_data, (h, w))
     return image
 
+
 def rescale_image(image, rescaleXY):
     w, h = rescaleXY
     return cv2.resize(image, (h, w), interpolation=cv2.INTER_NEAREST)
 
+
 def assign_labels_to_image(image, labelfile):
-    w,h = image.shape
+    w, h = image.shape
     allen_id_image = np.zeros((h, w))  # create an empty image array
     coordsy, coordsx = np.meshgrid(list(range(w)), list(range(h)))
- 
+
     values = image[coordsy, coordsx]
     lbidx = labelfile["idx"].values
 
     allen_id_image = lbidx[values.astype(int)]
     return allen_id_image
 
+
 def count_pixels_per_label(image):
     unique_ids, counts = np.unique(image, return_counts=True)
     area_per_label = list(zip(unique_ids, counts))
     df_area_per_label = pd.DataFrame(area_per_label, columns=["idx", "region_area"])
     return df_area_per_label
 
-def flat_to_dataframe(labelfile, file=None,  rescaleXY=None, image_vector=None, volume=None):
+
+def flat_to_dataframe(
+    labelfile, file=None, rescaleXY=None, image_vector=None, volume=None
+):
     if (image_vector is not None) and (volume is not None):
         image = generate_target_slice(image_vector, volume)
         image = np.float64(image)
@@ -186,8 +199,8 @@ def flat_to_dataframe(labelfile, file=None,  rescaleXY=None, image_vector=None,
         image = read_flat_file(file)
     elif file.endswith(".seg"):
         image = read_seg_file(file)
-    print('datatype', image.dtype)
-    print('image shape open', image.shape)
+    print("datatype", image.dtype)
+    print("image shape open", image.shape)
 
     if rescaleXY:
         image = rescale_image(image, rescaleXY)
@@ -196,4 +209,4 @@ def flat_to_dataframe(labelfile, file=None,  rescaleXY=None, image_vector=None,
     else:
         allen_id_image = image
     df_area_per_label = count_pixels_per_label(allen_id_image)
-    return df_area_per_label
\ No newline at end of file
+    return df_area_per_label
diff --git a/PyNutil/generate_target_slice.py b/PyNutil/generate_target_slice.py
index 9cd83c7..31681b8 100644
--- a/PyNutil/generate_target_slice.py
+++ b/PyNutil/generate_target_slice.py
@@ -29,8 +29,12 @@ def generate_target_slice(alignment, volume):
     Z_Coords = np.round(Z_Coords).astype(int)
 
     out_bounds_Coords = (
-        (X_Coords > bounds[0]) | (Y_Coords > bounds[1]) | (Z_Coords > bounds[2]) 
-        | (X_Coords < 0) | (Y_Coords < 0) | (Z_Coords < 0)
+        (X_Coords > bounds[0])
+        | (Y_Coords > bounds[1])
+        | (Z_Coords > bounds[2])
+        | (X_Coords < 0)
+        | (Y_Coords < 0)
+        | (Z_Coords < 0)
     )
     X_pad = X_Coords.copy()
     Y_pad = Y_Coords.copy()
diff --git a/PyNutil/load_workflow.py b/PyNutil/load_workflow.py
index ac3dd3d..9675196 100644
--- a/PyNutil/load_workflow.py
+++ b/PyNutil/load_workflow.py
@@ -6,7 +6,7 @@ import pandas as pd
 import cv2
 import numpy as np
 
-#from read_and_write import flat_to_array, label_to_array
+# from read_and_write import flat_to_array, label_to_array
 from counting_and_load import flat_to_dataframe
 
 base = r"../test_data/tTA_2877_NOP_s037_atlasmap/2877_NOP_tTA_lacZ_Xgal_s037_nl.flat"
@@ -14,21 +14,21 @@ label = r"../annotation_volumes\allen2017_colours.csv"
 ##optional
 seg = r"../test_data/tTA_2877_NOP_s037_seg/2877_NOP_tTA_lacZ_Xgal_resize_Simple_Seg_s037.png"
 segim = cv2.imread(seg)
-#the indexing [:2] means the first two values and [::-1] means reverse the list
+# the indexing [:2] means the first two values and [::-1] means reverse the list
 segXY = segim.shape[:2][::-1]
-#image_arr = flat_to_array(base, label)
+# image_arr = flat_to_array(base, label)
 
-#plt.imshow(flat_to_array(base, label))
+# plt.imshow(flat_to_array(base, label))
 
 df_area_per_label = flat_to_dataframe(base, label, segXY)
 
 """count pixels in np array for unique idx, return pd df"""
-#unique_ids, counts = np.unique(allen_id_image, return_counts=True)
+# unique_ids, counts = np.unique(allen_id_image, return_counts=True)
 
-#area_per_label = list(zip(unique_ids, counts))
+# area_per_label = list(zip(unique_ids, counts))
 # create a list of unique regions and pixel counts per region
 
-#df_area_per_label = pd.DataFrame(area_per_label, columns=["idx", "area_count"])
+# df_area_per_label = pd.DataFrame(area_per_label, columns=["idx", "area_count"])
 # create a pandas df with regions and pixel counts
 
 
diff --git a/PyNutil/main.py b/PyNutil/main.py
index 6277a1f..44ac2d4 100644
--- a/PyNutil/main.py
+++ b/PyNutil/main.py
@@ -8,7 +8,6 @@ from datetime import datetime
 import os
 
 
-
 class PyNutil:
     """A utility class for working with brain atlases and segmentation data.
 
@@ -132,9 +131,10 @@ class PyNutil:
         atlas_labels = pd.read_csv(f"{atlas_root_path}{atlas_label_path}")
         print("atlas labels loaded ✅")
         return atlas_volume, atlas_labels
-    
 
-    def get_coordinates(self, non_linear=True, method="all", object_cutoff=0, use_flat=False):
+    def get_coordinates(
+        self, non_linear=True, method="all", object_cutoff=0, use_flat=False
+    ):
         """Extracts pixel coordinates from the segmentation data.
 
         Parameters
@@ -178,7 +178,7 @@ class PyNutil:
             method=method,
             object_cutoff=object_cutoff,
             atlas_volume=self.atlas_volume,
-            use_flat=use_flat
+            use_flat=use_flat,
         )
         self.pixel_points = pixel_points
         self.centroids = centroids
@@ -221,7 +221,9 @@ class PyNutil:
         current_points = None
         print("region areas list")
         print(self.region_areas_list)
-        for pl,cl,ra in zip(self.points_len, self.centroids_len, self.region_areas_list):
+        for pl, cl, ra in zip(
+            self.points_len, self.centroids_len, self.region_areas_list
+        ):
             if hasattr(self, "centroids"):
                 current_centroids = labeled_points_centroids[prev_cl : prev_cl + cl]
             if hasattr(self, "pixel_points"):
@@ -231,41 +233,52 @@ class PyNutil:
             )
             print("current df", current_df)
 
-# create the df for section report and all report
-# pixel_count_per_region returns a df with idx, pixel count, name and RGB.
-# ra is region area list from 
-# merge current_df onto ra (region_areas_list) based on idx column
-#(left means use only keys from left frame, preserve key order)
-            
+            # create the df for section report and all report
+            # pixel_count_per_region returns a df with idx, pixel count, name and RGB.
+            # ra is region area list from
+            # merge current_df onto ra (region_areas_list) based on idx column
+            # (left means use only keys from left frame, preserve key order)
+
             """
             Merge region areas and object areas onto the atlas label file.
             Remove duplicate columns
             Calculate and add area_fraction to new column in the df.  
             """
-            
-            all_region_df = self.atlas_labels.merge(ra, on = 'idx', how='left')           
-            current_df_new = all_region_df.merge(current_df, on= 'idx', how= 'left', suffixes= (None,"_y")).drop(columns=["a","VIS", "MSH", "name_y","r_y","g_y","b_y"])
-            current_df_new["area_fraction"] = current_df_new["pixel_count"] / current_df_new["region_area"]
+
+            all_region_df = self.atlas_labels.merge(ra, on="idx", how="left")
+            current_df_new = all_region_df.merge(
+                current_df, on="idx", how="left", suffixes=(None, "_y")
+            ).drop(columns=["a", "VIS", "MSH", "name_y", "r_y", "g_y", "b_y"])
+            current_df_new["area_fraction"] = (
+                current_df_new["pixel_count"] / current_df_new["region_area"]
+            )
             current_df_new.fillna(0, inplace=True)
             per_section_df.append(current_df_new)
             prev_pl += pl
             prev_cl += cl
-        
-        
+
         ##combine all the slice reports, groupby idx, name, rgb and sum region and object pixels. Remove area_fraction column and recalculate.
-        self.label_df =  pd.concat(per_section_df).groupby(['idx','name','r','g','b']).sum().reset_index().drop(columns=['area_fraction'])
-        self.label_df["area_fraction"] = self.label_df["pixel_count"] / self.label_df["region_area"]
+        self.label_df = (
+            pd.concat(per_section_df)
+            .groupby(["idx", "name", "r", "g", "b"])
+            .sum()
+            .reset_index()
+            .drop(columns=["area_fraction"])
+        )
+        self.label_df["area_fraction"] = (
+            self.label_df["pixel_count"] / self.label_df["region_area"]
+        )
         self.label_df.fillna(0, inplace=True)
         """
         Potential source of error:
         If there are duplicates in the label file, regional results will be duplicated and summed leading to incorrect results
         """
 
-        #reorder the df to match the order of idx column in self.atlas_labels        
-        self.label_df = self.label_df.set_index('idx')
-        self.label_df = self.label_df.reindex(index=self.atlas_labels['idx'])
+        # reorder the df to match the order of idx column in self.atlas_labels
+        self.label_df = self.label_df.set_index("idx")
+        self.label_df = self.label_df.reindex(index=self.atlas_labels["idx"])
         self.label_df = self.label_df.reset_index()
-        
+
         self.labeled_points = labeled_points
         self.labeled_points_centroids = labeled_points_centroids
         self.per_section_df = per_section_df
@@ -289,7 +302,7 @@ class PyNutil:
         """
         if not os.path.exists(output_folder):
             os.makedirs(output_folder)
-            
+
         if not os.path.exists(f"{output_folder}/whole_series_report"):
             os.makedirs(f"{output_folder}/whole_series_report")
 
@@ -299,9 +312,11 @@ class PyNutil:
                 "if you want to save the quantification please run quantify_coordinates"
             )
         else:
-            
             self.label_df.to_csv(
-                f"{output_folder}/whole_series_report/counts.csv", sep=";", na_rep="", index=False
+                f"{output_folder}/whole_series_report/counts.csv",
+                sep=";",
+                na_rep="",
+                index=False,
             )
         if not os.path.exists(f"{output_folder}/per_section_meshview"):
             os.makedirs(f"{output_folder}/per_section_meshview")
diff --git a/PyNutil/propagation.py b/PyNutil/propagation.py
index d4af1e8..1f3b643 100644
--- a/PyNutil/propagation.py
+++ b/PyNutil/propagation.py
@@ -1,121 +1,132 @@
-import math,re
+import math, re
+
 
 def propagate(arr):
-  for slice in arr:
-    if "nr" not in slice:
-      slice["nr"]=int(re.search(r"_s(\d+)",slice["filename"]).group(1))
-
-  arr.sort(key=lambda slice:slice["nr"])
-  
-  linregs=[LinReg() for i in range(11)]
-  count=0
-  for slice in arr:
-    if "anchoring" in slice:
-      a=slice["anchoring"]
-      for i in range(3):
-        a[i]+=(a[i+3]+a[i+6])/2
-      a.extend([normalize(a,3)/slice["width"],normalize(a,6)/slice["height"]])
-      for i in range(len(linregs)):
-        linregs[i].add(slice["nr"],a[i])
-      count+=1
-
-  if count>=2:
-    l=len(arr)
-    if not "anchoring" in arr[0]:
-      nr=arr[0]["nr"]
-      a=[linreg.get(nr) for linreg in linregs]
-      orthonormalize(a)
-      arr[0]["anchoring"]=a
-      count+=1
-    if not "anchoring" in arr[l-1]:
-      nr=arr[l-1]["nr"]
-      a=[linreg.get(nr) for linreg in linregs]
-      orthonormalize(a)
-      arr[l-1]["anchoring"]=a
-      count+=1
-
-    start=1
-    while count<l:
-      while "anchoring" in arr[start]:
-        start+=1
-      next=start+1
-      while not "anchoring" in arr[next]:
-        next+=1
-      pnr=arr[start-1]["nr"]
-      nnr=arr[next]["nr"]
-      panch=arr[start-1]["anchoring"]
-      nanch=arr[next]["anchoring"]
-      linints=[LinInt(pnr,panch[i],nnr,nanch[i]) for i in range(len(panch))]
-      for i in range(start,next):
-        nr=arr[i]["nr"]
-        arr[i]["anchoring"]=[linint.get(nr) for linint in linints]
-        count+=1
-      start=next+1
+    for slice in arr:
+        if "nr" not in slice:
+            slice["nr"] = int(re.search(r"_s(\d+)", slice["filename"]).group(1))
 
+    arr.sort(key=lambda slice: slice["nr"])
+
+    linregs = [LinReg() for i in range(11)]
+    count = 0
     for slice in arr:
-      a=slice["anchoring"]
-      orthonormalize(a)
-      v=a.pop()
-      u=a.pop()
-      for i in range(3):
-        a[i+3]*=u*slice["width"]
-        a[i+6]*=v*slice["height"]
-        a[i]-=(a[i+3]+a[i+6])/2
-  return arr
+        if "anchoring" in slice:
+            a = slice["anchoring"].copy()
+            for i in range(3):
+                a[i] += (a[i + 3] + a[i + 6]) / 2
+            a.extend(
+                [normalize(a, 3) / slice["width"], normalize(a, 6) / slice["height"]]
+            )
+            for i in range(len(linregs)):
+                linregs[i].add(slice["nr"], a[i])
+            count += 1
+
+    if count >= 2:
+        l = len(arr)
+        if not "anchoring" in arr[0]:
+            nr = arr[0]["nr"]
+            a = [linreg.get(nr) for linreg in linregs]
+            orthonormalize(a)
+            arr[0]["anchoring"] = a
+            count += 1
+        if not "anchoring" in arr[l - 1]:
+            nr = arr[l - 1]["nr"]
+            a = [linreg.get(nr) for linreg in linregs]
+            orthonormalize(a)
+            arr[l - 1]["anchoring"] = a
+            count += 1
+
+        start = 1
+        while count < l:
+            while "anchoring" in arr[start]:
+                start += 1
+            next = start + 1
+            while not "anchoring" in arr[next]:
+                next += 1
+            pnr = arr[start - 1]["nr"]
+            nnr = arr[next]["nr"]
+            panch = arr[start - 1]["anchoring"]
+            nanch = arr[next]["anchoring"]
+            linints = [LinInt(pnr, panch[i], nnr, nanch[i]) for i in range(len(panch))]
+            for i in range(start, next):
+                nr = arr[i]["nr"]
+                arr[i]["anchoring"] = [linint.get(nr) for linint in linints]
+                count += 1
+            start = next + 1
+
+        for slice in arr:
+            a = slice["anchoring"]
+            orthonormalize(a)
+            v = a.pop()
+            u = a.pop()
+            for i in range(3):
+                a[i + 3] *= u * slice["width"]
+                a[i + 6] *= v * slice["height"]
+                a[i] -= (a[i + 3] + a[i + 6]) / 2
+    return arr
+
 
 class LinInt:
-  def __init__(self,x1,y1,x2,y2):
-    self.x1=x1
-    self.x2=x2
-    self.y1=y1
-    self.y2=y2
+    def __init__(self, x1, y1, x2, y2):
+        self.x1 = x1
+        self.x2 = x2
+        self.y1 = y1
+        self.y2 = y2
+
+    def get(self, x):
+        return self.y1 + (self.y2 - self.y1) * (x - self.x1) / (self.x2 - self.x1)
 
-  def get(self,x):
-    return self.y1+(self.y2-self.y1)*(x-self.x1)/(self.x2-self.x1)
 
 class LinReg:
-  def __init__(self):
-    self.n=0
-    self.Sx=0
-    self.Sy=0
-    self.Sxx=0
-    self.Sxy=0
-
-  def add(self,x,y):
-    self.n+=1
-    self.Sx+=x
-    self.Sy+=y
-    self.Sxx+=x*x
-    self.Sxy+=x*y
-    if self.n>=2:
-      self.b=(self.n*self.Sxy-self.Sx*self.Sy)/(self.n*self.Sxx-self.Sx*self.Sx)
-      self.a=self.Sy/self.n-self.b*self.Sx/self.n
-
-  def get(self,x):
-    return self.a+self.b*x
-
-def normalize(arr,idx):
-  l=0
-  for i in range(3):
-    l+=arr[idx+i]*arr[idx+i]
-  l=math.sqrt(l)
-  for i in range(3):
-    arr[idx+i]/=l
-  return l
+    def __init__(self):
+        self.n = 0
+        self.Sx = 0
+        self.Sy = 0
+        self.Sxx = 0
+        self.Sxy = 0
+
+    def add(self, x, y):
+        self.n += 1
+        self.Sx += x
+        self.Sy += y
+        self.Sxx += x * x
+        self.Sxy += x * y
+        if self.n >= 2:
+            self.b = (self.n * self.Sxy - self.Sx * self.Sy) / (
+                self.n * self.Sxx - self.Sx * self.Sx
+            )
+            self.a = self.Sy / self.n - self.b * self.Sx / self.n
+
+    def get(self, x):
+        return self.a + self.b * x
+
+
+def normalize(arr, idx):
+    l = 0
+    for i in range(3):
+        l += arr[idx + i] * arr[idx + i]
+    l = math.sqrt(l)
+    for i in range(3):
+        arr[idx + i] /= l
+    return l
+
 
 def orthonormalize(arr):
-  normalize(arr,3)
-  dot=0
-  for i in range(3):
-    dot+=arr[i+3]*arr[i+6]
-  for i in range(3):
-    arr[i+6]-=arr[i+3]*dot
-  normalize(arr,6)
-
-if __name__=="__main__":
-  import json,sys
-  with open(sys.argv[1]) as f:
-    series=json.load(f)
-  propagate(series["slices"])
-  with open(sys.argv[2],"w") as f:
-    json.dump(series,f)
+    normalize(arr, 3)
+    dot = 0
+    for i in range(3):
+        dot += arr[i + 3] * arr[i + 6]
+    for i in range(3):
+        arr[i + 6] -= arr[i + 3] * dot
+    normalize(arr, 6)
+
+
+if __name__ == "__main__":
+    import json, sys
+
+    with open(sys.argv[1]) as f:
+        series = json.load(f)
+    propagate(series["slices"])
+    with open(sys.argv[2], "w") as f:
+        json.dump(series, f)
diff --git a/PyNutil/read_and_write.py b/PyNutil/read_and_write.py
index ba5420f..8be7f08 100644
--- a/PyNutil/read_and_write.py
+++ b/PyNutil/read_and_write.py
@@ -8,6 +8,7 @@ import nrrd
 import re
 from .propagation import propagate
 
+
 # related to read and write
 # this function reads a VisuAlign JSON and returns the slices
 def load_visualign_json(filename):
@@ -24,19 +25,21 @@ def load_visualign_json(filename):
 
         name = os.path.basename(filename)
         lz_compat_file = {
-            "name":name,
-            "target":vafile["atlas"],
-            "target-resolution":[ 456, 528, 320],
-            "slices":slices,
+            "name": name,
+            "target": vafile["atlas"],
+            "target-resolution": [456, 528, 320],
+            "slices": slices,
         }
-          # save with .json extension need to see if i can remove this
-        with open(filename.replace(".waln", ".json").replace(".wwrp", ".json"), "w") as f:
+        # save with .json extension need to see if i can remove this
+        with open(
+            filename.replace(".waln", ".json").replace(".wwrp", ".json"), "w"
+        ) as f:
             json.dump(lz_compat_file, f, indent=4)
 
     else:
         slices = vafile["slices"]
-    
-    slices = propagate(slices)
+    if len(slices) > 1:
+        slices = propagate(slices)
     return slices
 
 
@@ -95,24 +98,27 @@ def flat_to_array(file, labelfile):
             # It has the shape width times height
             data = struct.unpack(">" + ("xBH"[b] * (w * h)), f.read(b * w * h))
     elif file.endswith(".seg"):
-        with open(file,"rb") as f:
+        with open(file, "rb") as f:
+
             def byte():
                 return f.read(1)[0]
+
             def code():
-                c=byte()
-                if(c<0):
+                c = byte()
+                if c < 0:
                     raise "!"
-                return c if c<128 else (c&127)|(code()<<7)
+                return c if c < 128 else (c & 127) | (code() << 7)
+
             if "SegRLEv1" != f.read(8).decode():
                 raise "Header mismatch"
-            atlas=f.read(code()).decode()
+            atlas = f.read(code()).decode()
             print(f"Target atlas: {atlas}")
-            codes=[code() for x in range(code())]
-            w=code()
-            h=code()
-            data=[]
-            while len(data)<w*h:
-                data += [codes[byte() if len(codes)<=256 else code()]]*(code()+1)
+            codes = [code() for x in range(code())]
+            w = code()
+            h = code()
+            data = []
+            while len(data) < w * h:
+                data += [codes[byte() if len(codes) <= 256 else code()]] * (code() + 1)
 
     # convert flat file data into an array, previously data was a tuple
     imagedata = np.array(data)
@@ -124,13 +130,15 @@ def flat_to_array(file, labelfile):
             image[y, x] = imagedata[x + y * w]
 
     image_arr = np.array(image)
-    #return image_arr
+    # return image_arr
 
     """assign label file values into image array"""
     labelfile = pd.read_csv(labelfile)
     allen_id_image = np.zeros((h, w))  # create an empty image array
     coordsy, coordsx = np.meshgrid(list(range(w)), list(range(h)))
-    values = image_arr[coordsx, coordsy]  # assign x,y coords from image_array into values
+    values = image_arr[
+        coordsx, coordsy
+    ]  # assign x,y coords from image_array into values
     lbidx = labelfile["idx"].values
     allen_id_image = lbidx[values.astype(int)]
     return allen_id_image
diff --git a/PyNutil/reconstruct_dzi.py b/PyNutil/reconstruct_dzi.py
index 8a43697..bbdff40 100644
--- a/PyNutil/reconstruct_dzi.py
+++ b/PyNutil/reconstruct_dzi.py
@@ -4,6 +4,7 @@ import os
 import zipfile
 import xmltodict
 
+
 def reconstruct_dzi(zip_file_path):
     """
     Reconstructs a Deep Zoom Image (DZI) from a zip file containing the tiles.
@@ -24,15 +25,21 @@ def reconstruct_dzi(zip_file_path):
 
         # Get the filenames of the highest level tiles
         highest_level_files = [
-            i for i in zip_file.namelist() if i.endswith(".png") and i.split("/")[-2] == highest_level
+            i
+            for i in zip_file.namelist()
+            if i.endswith(".png") and i.split("/")[-2] == highest_level
         ]
 
         # Read the DZI file
-        dzi_file = zip_file.open([i for i in zip_file.namelist() if i.endswith(".dzi")][0])
+        dzi_file = zip_file.open(
+            [i for i in zip_file.namelist() if i.endswith(".dzi")][0]
+        )
         xml = dzi_file.read()
         json_data = xmltodict.parse(xml)
         tileSize = json_data["Image"]["@TileSize"]
-        width, height = int(json_data["Image"]["Size"]["@Width"]), int(json_data["Image"]["Size"]["@Height"])
+        width, height = int(json_data["Image"]["Size"]["@Width"]), int(
+            json_data["Image"]["Size"]["@Height"]
+        )
 
         # Create an empty image
         image = np.zeros((height, width, 3), dtype=np.uint8)
@@ -48,4 +55,4 @@ def reconstruct_dzi(zip_file_path):
             image[y : y + image_.shape[0], x : x + image_.shape[1], :] = image_
 
         # Save the image
-    return image
\ No newline at end of file
+    return image
diff --git a/PyNutil/visualign_deformations.py b/PyNutil/visualign_deformations.py
index 534dfa7..2caef65 100644
--- a/PyNutil/visualign_deformations.py
+++ b/PyNutil/visualign_deformations.py
@@ -2,12 +2,13 @@
 import numpy as np
 from scipy.spatial import Delaunay
 
+
 def triangulate(w, h, markers):
     vertices = [
         [-0.1 * w, -0.1 * h, -0.1 * w, -0.1 * h],
-        [ 1.1 * w, -0.1 * h,  1.1 * w, -0.1 * h],
-        [-0.1 * w,  1.1 * h, -0.1 * w,  1.1 * h],
-        [ 1.1 * w,  1.1 * h,  1.1 * w,  1.1 * h],
+        [1.1 * w, -0.1 * h, 1.1 * w, -0.1 * h],
+        [-0.1 * w, 1.1 * h, -0.1 * w, 1.1 * h],
+        [1.1 * w, 1.1 * h, 1.1 * w, 1.1 * h],
     ]
 
     edges = [0] * ((len(markers) + 4) * (len(markers) + 4 - 1) // 2)
@@ -155,7 +156,7 @@ class Triangle:
             [[bx - ax, by - ay, 0], [cx - ax, cy - ay, 0], [ax, ay, 1]]
         )
         if self.decomp == None:
-            print('e')
+            print("e")
         a2 = distsquare(bx, by, cx, cy)
         b2 = distsquare(ax, ay, cx, cy)
         c2 = distsquare(ax, ay, bx, by)
@@ -190,7 +191,6 @@ class Triangle:
 
     # xy: 2-dimensional array with one xy-pair per row
     def inforward_vec(self, x, y, xPrime, yPrime):
-
         uv1 = rowmul3_vec(x, y, self.forwarddecomp)
         # also compute the next step, since it uses the parameters of this triangle
         ok = (
@@ -213,7 +213,7 @@ class Triangle:
 
     def intriangle_vec(self, x, y, xPrime, yPrime):
         if self.decomp is None:
-            print('e')
+            print("e")
         uv1 = rowmul3_vec(x, y, self.decomp)
         # also compute the next step, since it uses the parameters of this triangle
         ok = (
@@ -233,5 +233,3 @@ class Triangle:
             + (self.B[1] - self.A[1]) * uv1[ok, 0]
             + (self.C[1] - self.A[1]) * uv1[ok, 1]
         )
-
-
diff --git a/messing_around_files/pyflat.py b/messing_around_files/pyflat.py
index cbe6605..f4fbfb5 100644
--- a/messing_around_files/pyflat.py
+++ b/messing_around_files/pyflat.py
@@ -1,17 +1,17 @@
-
 """This is Gergely Csusc's code from VisuAlign MediaWiki NITRC page,
-this was a test, not used elsewhere in PyNutil"""   
+this was a test, not used elsewhere in PyNutil"""
 
 import sys
+
 for arg in sys.argv:
     if arg.startswith("flat="):
-        flatfile=arg[len("flat="):]
+        flatfile = arg[len("flat=") :]
     if arg.startswith("label="):
-        labelfile=arg[len("label="):]
+        labelfile = arg[len("label=") :]
     if arg.startswith("json="):
-        jsonfile=arg[len("json="):]
+        jsonfile = arg[len("json=") :]
     if arg.startswith("output="):
-        outfile=arg[len("output="):]
+        outfile = arg[len("output=") :]
 if "flatfile" not in vars():
     print("flat=<some .flat file> parameter missing")
     sys.exit()
@@ -19,31 +19,37 @@ if "outfile" not in vars():
     print("output=<new .png file> parameter missing")
     sys.exit()
 
-palette=False
+palette = False
 if "labelfile" in vars():
     import re
-    palette=[]
+
+    palette = []
     with open(labelfile) as f:
         for line in f:
-            lbl=re.match(r'\s*\d+\s+(\d+)\s+(\d+)\s+(\d+)',line)
+            lbl = re.match(r"\s*\d+\s+(\d+)\s+(\d+)\s+(\d+)", line)
             if lbl:
-                palette.append((int(lbl[1]),int(lbl[2]),int(lbl[3])))
+                palette.append((int(lbl[1]), int(lbl[2]), int(lbl[3])))
     print(f"{len(palette)} labels parsed")
 elif "jsonfile" in vars():
     import json
+
     with open(jsonfile) as f:
-        palette=[(i["red"],i["green"],i["blue"]) for i in json.load(f)]
+        palette = [(i["red"], i["green"], i["blue"]) for i in json.load(f)]
     print(f"{len(palette)} labels loaded")
 
 import struct
-with open(flatfile,"rb") as f:
-    b,w,h=struct.unpack(">BII",f.read(9))
-    data=struct.unpack(">"+("xBH"[b]*(w*h)),f.read(b*w*h))
+
+with open(flatfile, "rb") as f:
+    b, w, h = struct.unpack(">BII", f.read(9))
+    data = struct.unpack(">" + ("xBH"[b] * (w * h)), f.read(b * w * h))
 print(f"{b} bytes per pixel, {w} x {h} resolution")
 
 import PIL.Image
-image=PIL.Image.new("RGB" if palette else "L",(w,h))
+
+image = PIL.Image.new("RGB" if palette else "L", (w, h))
 for y in range(h):
     for x in range(w):
-        image.putpixel((x,y),palette[data[x+y*w]] if palette else data[x+y*w] & 255)
-image.save(outfile,"PNG")
\ No newline at end of file
+        image.putpixel(
+            (x, y), palette[data[x + y * w]] if palette else data[x + y * w] & 255
+        )
+image.save(outfile, "PNG")
diff --git a/messing_around_files/testing_openflatfile.py b/messing_around_files/testing_openflatfile.py
index 1b076ba..a52502b 100644
--- a/messing_around_files/testing_openflatfile.py
+++ b/messing_around_files/testing_openflatfile.py
@@ -39,15 +39,15 @@ with open(base, "rb") as f:
 """assign label file values into image array"""
 
 labelfile = pd.read_csv(r"annotation_volumes\allen2017_colours.csv")
-#labelfile[]
-print(list(zip(val,count)))
+# labelfile[]
+print(list(zip(val, count)))
 
 
-temp_copy = labelfile.loc[val.astype(int),:].copy()
+temp_copy = labelfile.loc[val.astype(int), :].copy()
 
-temp_copy['region areas'] = count
+temp_copy["region areas"] = count
 
-temp_copy.to_csv('../outputs/region_areas_quick_test.csv',sep=';')
+temp_copy.to_csv("../outputs/region_areas_quick_test.csv", sep=";")
 
 allen_id_image = np.zeros((h, w))  # create an empty image array
 
diff --git a/scripts/create_test_data.py b/scripts/create_test_data.py
index 1e196fe..4746729 100644
--- a/scripts/create_test_data.py
+++ b/scripts/create_test_data.py
@@ -3,15 +3,16 @@ from PIL import Image, ImageDraw
 
 def generate_test_image(width, height, file_path):
     # Create an empty white image
-    image = Image.new(mode = "RGB", size = (width, height), color=(255,255,255))
+    image = Image.new(mode="RGB", size=(width, height), color=(255, 255, 255))
 
     # Save the image as a PNG file
     image.save(file_path)
 
+
 # Example usage
 width = 1000  # Specify the width of the image in pixels
 height = 1000  # Specify the height of the image in pixels
-file_path = 'testimage.png'  # Specify the file path for saving the image
+file_path = "testimage.png"  # Specify the file path for saving the image
 
 # Generate and save the black and white image
 generate_test_image(width, height, file_path)
@@ -19,10 +20,13 @@ generate_test_image(width, height, file_path)
 
 """This is used to generate the test data"""
 
-def generate_image_with_squares(width, height, square_diameter, square_locations, num_images):
+
+def generate_image_with_squares(
+    width, height, square_diameter, square_locations, num_images
+):
     # Create a white image with objects of specified size at specified x, y locations
     for i in range(1, num_images + 1):
-        image = Image.new('RGB', (width, height), color=(255, 255, 255))
+        image = Image.new("RGB", (width, height), color=(255, 255, 255))
 
         # Create a draw object
         draw = ImageDraw.Draw(image)
@@ -37,13 +41,22 @@ def generate_image_with_squares(width, height, square_diameter, square_locations
         file_name = f"../test_data/PyTest/test_s00{i}.png"
         image.save(file_name, "PNG")
 
+
 # Example usage
 width = 1500  # Specify the width of the image in pixels
-height = 1000 # Specify the height of the image in pixels
+height = 1000  # Specify the height of the image in pixels
 square_diameter = 10  # Specify the size of the black squares in pixels
-square_locations = [(500, 500), (500, 600), (500, 700), (1000, 500), (1000,600),(1000,700)]  # Specify the x, y locations of the black squares
+square_locations = [
+    (500, 500),
+    (500, 600),
+    (500, 700),
+    (1000, 500),
+    (1000, 600),
+    (1000, 700),
+]  # Specify the x, y locations of the black squares
 num_images = 5
 
 # Generate the white image with black squares
-image = generate_image_with_squares(width, height, square_diameter, square_locations,num_images)
-
+image = generate_image_with_squares(
+    width, height, square_diameter, square_locations, num_images
+)
diff --git a/testOOP.py b/testOOP.py
index 8075fb8..368f2c4 100644
--- a/testOOP.py
+++ b/testOOP.py
@@ -1,7 +1,7 @@
 from PyNutil import PyNutil
 
 pnt = PyNutil(settings_file=r"PyNutil/test/test8_PyNutil_fixed.json")
-##Use flat can be set to True if you want to use the flat file 
+##Use flat can be set to True if you want to use the flat file
 # instead of the visualign json (this is only useful for testing and will be removed)
 pnt.get_coordinates(object_cutoff=0, use_flat=False)
 
@@ -10,4 +10,4 @@ pnt.quantify_coordinates()
 pnt.save_analysis("PyNutil/outputs/test8_PyNutil")
 
 # remove name, r, g, b, from pixel_
-# add to region_areas df
\ No newline at end of file
+# add to region_areas df
-- 
GitLab