Repository: fish-quant/big-fish (language: python)

Issue:
allow int 32-bit as input for numerous functions + minor refactoring
Close #67 
Close fish-quant/big-fish-examples#9


Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index 8620829..eb7d1fc 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ Big-FISH requires Python 3.6 or newer. Additionally, it has the following depend
 
 - numpy (>= 1.16.0)
 - scipy (>= 1.4.1)
-- scikit-learn (>= 0.21.0)
+- scikit-learn (>= 0.24.0)
 - scikit-image (>= 0.14.2)
 - matplotlib (>= 3.0.2)
 - pandas (>= 0.24.0)
diff --git a/bigfish/__init__.py b/bigfish/__init__.py
index 39b1340..f946f79 100644
--- a/bigfish/__init__.py
+++ b/bigfish/__init__.py
@@ -12,4 +12,4 @@
 # MINOR: new features
 # PATCH: backwards compatible bug fixes
 # MAJOR.MINOR.PATCHdev means a version under development
-__version__ = "0.6.1"
+__version__ = "0.6.2"
diff --git a/bigfish/classification/features.py b/bigfish/classification/features.py
index 53ed099..ab38a49 100644
--- a/bigfish/classification/features.py
+++ b/bigfish/classification/features.py
@@ -11,24 +11,37 @@
 from scipy import ndimage as ndi
 
 from skimage.morphology import binary_opening
-from skimage.morphology.selem import disk
+import skimage
+from sklearn.utils.fixes import parse_version
+if parse_version(skimage.__version__) < parse_version("0.19.0"):
+    from skimage.morphology.selem import disk
+else:
+    from skimage.morphology.footprints import disk
 
 import bigfish.stack as stack
 from .input_preparation import prepare_extracted_data
 
 
-# TODO allow RNA coordinates in float64 and int64
-
 # ### Main functions ###
 
-def compute_features(cell_mask, nuc_mask, ndim, rna_coord, smfish=None,
-                     voxel_size_yx=None, foci_coord=None,
-                     centrosome_coord=None,
-                     compute_distance=False, compute_intranuclear=False,
-                     compute_protrusion=False, compute_dispersion=False,
-                     compute_topography=False, compute_foci=False,
-                     compute_area=False, compute_centrosome=False,
-                     return_names=False):
+def compute_features(
+        cell_mask,
+        nuc_mask,
+        ndim,
+        rna_coord,
+        smfish=None,
+        voxel_size_yx=None,
+        foci_coord=None,
+        centrosome_coord=None,
+        compute_distance=False,
+        compute_intranuclear=False,
+        compute_protrusion=False,
+        compute_dispersion=False,
+        compute_topography=False,
+        compute_foci=False,
+        compute_area=False,
+        compute_centrosome=False,
+        return_names=False):
     """Compute requested features.
 
     Parameters
@@ -39,7 +52,7 @@ def compute_features(cell_mask, nuc_mask, ndim, rna_coord, smfish=None,
         Surface of the nucleus with shape (y, x).
     ndim : int
         Number of spatial dimensions to consider (2 or 3).
-    rna_coord : np.ndarray, np.int64
+    rna_coord : np.ndarray, np.int
         Coordinates of the detected spots with shape (nb_spots, 4) or
         (nb_spots, 3). One coordinate per dimension (zyx or yx dimensions)
         plus the index of the cluster assigned to the spot. If no cluster was
@@ -49,11 +62,11 @@ def compute_features(cell_mask, nuc_mask, ndim, rna_coord, smfish=None,
         Image of RNAs, with shape (y, x).
     voxel_size_yx : int, float or None
         Size of a voxel on the yx plan, in nanometer.
-    foci_coord : np.ndarray, np.int64
+    foci_coord : np.ndarray, np.int
         Array with shape (nb_foci, 5) or (nb_foci, 4). One coordinate per
         dimension for the foci centroid (zyx or yx coordinates), the number of
         spots detected in the foci and its index.
-    centrosome_coord : np.ndarray, np.int64
+    centrosome_coord : np.ndarray, np.int
         Coordinates of the detected centrosome with shape (nb_elements, 3) or
         (nb_elements, 2). One coordinate per dimension (zyx or yx dimensions).
         These coordinates are mandatory to compute centrosome related features.
@@ -83,22 +96,23 @@ def compute_features(cell_mask, nuc_mask, ndim, rna_coord, smfish=None,
 
     """
     # check parameters
-    stack.check_parameter(voxel_size_yx=(int, float, type(None)),
-                          compute_distance=bool,
-                          compute_intranuclear=bool,
-                          compute_protrusion=bool,
-                          compute_dispersion=bool,
-                          compute_topography=bool,
-                          compute_foci=bool,
-                          compute_area=bool,
-                          compute_centrosome=bool,
-                          return_names=bool)
+    stack.check_parameter(
+        voxel_size_yx=(int, float, type(None)),
+        compute_distance=bool,
+        compute_intranuclear=bool,
+        compute_protrusion=bool,
+        compute_dispersion=bool,
+        compute_topography=bool,
+        compute_foci=bool,
+        compute_area=bool,
+        compute_centrosome=bool,
+        return_names=bool)
     if smfish is not None:
         stack.check_array(smfish, ndim=[2, 3], dtype=[np.uint8, np.uint16])
         if smfish.ndim == 3:
             smfish = stack.maximum_projection(smfish)
     if foci_coord is not None:
-        stack.check_array(foci_coord, ndim=2, dtype=np.int64)
+        stack.check_array(foci_coord, ndim=2, dtype=[np.int32, np.int64])
 
     # prepare input data
     (cell_mask,
@@ -213,14 +227,15 @@ def compute_features(cell_mask, nuc_mask, ndim, rna_coord, smfish=None,
     return features
 
 
-def get_features_name(names_features_distance=False,
-                      names_features_intranuclear=False,
-                      names_features_protrusion=False,
-                      names_features_dispersion=False,
-                      names_features_topography=False,
-                      names_features_foci=False,
-                      names_features_area=False,
-                      names_features_centrosome=False):
+def get_features_name(
+        names_features_distance=False,
+        names_features_intranuclear=False,
+        names_features_protrusion=False,
+        names_features_dispersion=False,
+        names_features_topography=False,
+        names_features_foci=False,
+        names_features_area=False,
+        names_features_centrosome=False):
     """Return the current list of features names.
 
     Parameters
@@ -251,84 +266,99 @@ def get_features_name(names_features_distance=False,
 
     """
     # check parameters
-    stack.check_parameter(names_features_distance=bool,
-                          names_features_intranuclear=bool,
-                          names_features_protrusion=bool,
-                          names_features_dispersion=bool,
-                          names_features_topography=bool,
-                          names_features_foci=bool,
-                          names_features_area=bool,
-                          names_features_centrosome=bool)
+    stack.check_parameter(
+        names_features_distance=bool,
+        names_features_intranuclear=bool,
+        names_features_protrusion=bool,
+        names_features_dispersion=bool,
+        names_features_topography=bool,
+        names_features_foci=bool,
+        names_features_area=bool,
+        names_features_centrosome=bool)
 
     # initialization
     features_name = []
 
     # get feature names
     if names_features_distance:
-        features_name += ["index_mean_distance_cell",
-                          "index_median_distance_cell",
-                          "index_mean_distance_nuc",
-                          "index_median_distance_nuc"]
+        features_name += [
+            "index_mean_distance_cell",
+            "index_median_distance_cell",
+            "index_mean_distance_nuc",
+            "index_median_distance_nuc"]
 
     if names_features_intranuclear:
-        features_name += ["proportion_rna_in_nuc",
-                          "nb_rna_out_nuc",
-                          "nb_rna_in_nuc"]
+        features_name += [
+            "proportion_rna_in_nuc",
+            "nb_rna_out_nuc",
+            "nb_rna_in_nuc"]
 
     if names_features_protrusion:
-        features_name += ["index_rna_protrusion",
-                          "proportion_rna_protrusion",
-                          "protrusion_area"]
+        features_name += [
+            "index_rna_protrusion",
+            "proportion_rna_protrusion",
+            "protrusion_area"]
 
     if names_features_dispersion:
-        features_name += ["index_polarization",
-                          "index_dispersion",
-                          "index_peripheral_distribution"]
+        features_name += [
+            "index_polarization",
+            "index_dispersion",
+            "index_peripheral_distribution"]
 
     if names_features_topography:
-        features_name += ["index_rna_nuc_edge",
-                          "proportion_rna_nuc_edge"]
+        features_name += [
+            "index_rna_nuc_edge",
+            "proportion_rna_nuc_edge"]
 
         a = 500
         for b in range(1000, 3001, 500):
-            features_name += ["index_rna_nuc_radius_{}_{}".format(a, b),
-                              "proportion_rna_nuc_radius_{}_{}".format(a, b)]
+            features_name += [
+                "index_rna_nuc_radius_{}_{}".format(a, b),
+                "proportion_rna_nuc_radius_{}_{}".format(a, b)]
             a = b
 
         a = 0
         for b in range(500, 3001, 500):
-            features_name += ["index_rna_cell_radius_{}_{}".format(a, b),
-                              "proportion_rna_cell_radius_{}_{}".format(a, b)]
+            features_name += [
+                "index_rna_cell_radius_{}_{}".format(a, b),
+                "proportion_rna_cell_radius_{}_{}".format(a, b)]
             a = b
 
     if names_features_foci:
         features_name += ["proportion_rna_in_foci"]
 
     if names_features_area:
-        features_name += ["proportion_nuc_area",
-                          "cell_area",
-                          "nuc_area",
-                          "cell_area_out_nuc"]
+        features_name += [
+            "proportion_nuc_area",
+            "cell_area",
+            "nuc_area",
+            "cell_area_out_nuc"]
 
     if names_features_centrosome:
-        features_name += ["index_mean_distance_centrosome",
-                          "index_median_distance_centrosome",
-                          "index_rna_centrosome",
-                          "proportion_rna_centrosome",
-                          "index_centrosome_dispersion"]
+        features_name += [
+            "index_mean_distance_centrosome",
+            "index_median_distance_centrosome",
+            "index_rna_centrosome",
+            "proportion_rna_centrosome",
+            "index_centrosome_dispersion"]
 
     return features_name
 
 
 # ### Features functions ###
 
-def features_distance(rna_coord, distance_cell, distance_nuc, cell_mask, ndim,
-                      check_input=True):
+def features_distance(
+        rna_coord,
+        distance_cell,
+        distance_nuc,
+        cell_mask,
+        ndim,
+        check_input=True):
     """Compute distance related features.
 
     Parameters
     ----------
-    rna_coord : np.ndarray, np.int64
+    rna_coord : np.ndarray, np.int
         Coordinates of the detected RNAs with zyx or yx coordinates in the
         first 3 or 2 columns.
     distance_cell : np.ndarray, np.float32
@@ -360,7 +390,10 @@ def features_distance(rna_coord, distance_cell, distance_nuc, cell_mask, ndim,
         stack.check_parameter(ndim=int)
         if ndim not in [2, 3]:
             raise ValueError("'ndim' should be 2 or 3, not {0}.".format(ndim))
-        stack.check_array(rna_coord, ndim=2, dtype=np.int64)
+        stack.check_array(
+            rna_coord,
+            ndim=2,
+            dtype=[np.int32, np.int64])
         stack.check_array(
             distance_cell,
             ndim=2,
@@ -406,10 +439,10 @@ def features_in_out_nucleus(rna_coord, rna_coord_out_nuc, check_input=True):
 
     Parameters
     ----------
-    rna_coord : np.ndarray, np.int64
+    rna_coord : np.ndarray, np.int
         Coordinates of the detected RNAs with zyx or yx coordinates in the
         first 3 or 2 columns.
-    rna_coord_out_nuc : np.ndarray, np.int64
+    rna_coord_out_nuc : np.ndarray, np.int
         Coordinates of the detected RNAs with zyx or yx coordinates in the
         first 3 or 2 columns. Spots detected inside the nucleus are removed.
     check_input : bool
@@ -428,8 +461,9 @@ def features_in_out_nucleus(rna_coord, rna_coord_out_nuc, check_input=True):
     # check parameters
     stack.check_parameter(check_input=bool)
     if check_input:
-        stack.check_array(rna_coord, ndim=2, dtype=np.int64)
-        stack.check_array(rna_coord_out_nuc, ndim=2, dtype=np.int64)
+        stack.check_array(rna_coord, ndim=2, dtype=[np.int32, np.int64])
+        stack.check_array(
+            rna_coord_out_nuc, ndim=2, dtype=[np.int32, np.int64])
 
     # count total number of rna
     nb_rna = float(len(rna_coord))
@@ -451,13 +485,18 @@ def features_in_out_nucleus(rna_coord, rna_coord_out_nuc, check_input=True):
     return features
 
 
-def features_protrusion(rna_coord, cell_mask, nuc_mask, ndim, voxel_size_yx,
-                        check_input=True):
+def features_protrusion(
+        rna_coord,
+        cell_mask,
+        nuc_mask,
+        ndim,
+        voxel_size_yx,
+        check_input=True):
     """Compute protrusion related features.
 
     Parameters
     ----------
-    rna_coord : np.ndarray, np.int64
+    rna_coord : np.ndarray, np.int
         Coordinates of the detected RNAs with zyx or yx coordinates in the
         first 3 or 2 columns.
     cell_mask : np.ndarray, bool
@@ -485,7 +524,6 @@ def features_protrusion(rna_coord, cell_mask, nuc_mask, ndim, voxel_size_yx,
     # TODO fin a better feature for the protrusion (idea: dilate region from
     #  centroid and stop when a majority of new pixels do not belong to the
     #  cell).
-
     # check parameters
     stack.check_parameter(check_input=bool)
     if check_input:
@@ -494,7 +532,7 @@ def features_protrusion(rna_coord, cell_mask, nuc_mask, ndim, voxel_size_yx,
             voxel_size_yx=(int, float))
         if ndim not in [2, 3]:
             raise ValueError("'ndim' should be 2 or 3, not {0}.".format(ndim))
-        stack.check_array(rna_coord, ndim=2, dtype=np.int64)
+        stack.check_array(rna_coord, ndim=2, dtype=[np.int32, np.int64])
         stack.check_array(cell_mask, ndim=2, dtype=bool)
         stack.check_array(nuc_mask, ndim=2, dtype=bool)
 
@@ -534,8 +572,15 @@ def features_protrusion(rna_coord, cell_mask, nuc_mask, ndim, voxel_size_yx,
     return features
 
 
-def features_dispersion(smfish, rna_coord, centroid_rna, cell_mask,
-                        centroid_cell, centroid_nuc, ndim, check_input=True):
+def features_dispersion(
+        smfish,
+        rna_coord,
+        centroid_rna,
+        cell_mask,
+        centroid_cell,
+        centroid_nuc,
+        ndim,
+        check_input=True):
     """Compute RNA Distribution Index features (RDI) described in:
 
     RDI Calculator: An analysis Tool to assess RNA distributions in cells,
@@ -545,16 +590,16 @@ def features_dispersion(smfish, rna_coord, centroid_rna, cell_mask,
     ----------
     smfish : np.ndarray, np.uint
         Image of RNAs, with shape (y, x).
-    rna_coord : np.ndarray, np.int64
+    rna_coord : np.ndarray, np.int
         Coordinates of the detected RNAs with zyx or yx coordinates in the
         first 3 or 2 columns.
-    centroid_rna : np.ndarray, np.int64
+    centroid_rna : np.ndarray, np.int
         Coordinates of the rna centroid with shape (2,) or (3,).
     cell_mask : np.ndarray, bool
         Surface of the cell with shape (y, x).
-    centroid_cell : np.ndarray, np.int64
+    centroid_cell : np.ndarray, np.int
         Coordinates of the cell centroid with shape (2,).
-    centroid_nuc : np.ndarray, np.int64
+    centroid_nuc : np.ndarray, np.int
         Coordinates of the nucleus centroid with shape (2,).
     ndim : int
         Number of spatial dimensions to consider.
@@ -578,11 +623,11 @@ def features_dispersion(smfish, rna_coord, centroid_rna, cell_mask,
         if ndim not in [2, 3]:
             raise ValueError("'ndim' should be 2 or 3, not {0}.".format(ndim))
         stack.check_array(smfish, ndim=2, dtype=[np.uint8, np.uint16])
-        stack.check_array(rna_coord, ndim=2, dtype=np.int64)
-        stack.check_array(centroid_rna, ndim=1, dtype=np.int64)
+        stack.check_array(rna_coord, ndim=2, dtype=[np.int32, np.int64])
+        stack.check_array(centroid_rna, ndim=1, dtype=[np.int32, np.int64])
         stack.check_array(cell_mask, ndim=2, dtype=bool)
-        stack.check_array(centroid_cell, ndim=1, dtype=np.int64)
-        stack.check_array(centroid_nuc, ndim=1, dtype=np.int64)
+        stack.check_array(centroid_cell, ndim=1, dtype=[np.int32, np.int64])
+        stack.check_array(centroid_nuc, ndim=1, dtype=[np.int32, np.int64])
 
     # case where no mRNAs are detected
     if len(rna_coord) == 0:
@@ -645,7 +690,7 @@ def _rmsd(coord, reference_coord):
 
     Parameters
     ----------
-    coord : np.ndarray, np.int64
+    coord : np.ndarray, np.int
         Coordinates with shape (nb_points, 2).
     reference_coord : np.ndarray, np.int64
         Reference coordinate to compute the distance from, with shape (2,).
@@ -664,14 +709,19 @@ def _rmsd(coord, reference_coord):
     return rmsd
 
 
-def features_topography(rna_coord, cell_mask, nuc_mask, cell_mask_out_nuc,
-                        ndim, voxel_size_yx,
-                        check_input=True):
+def features_topography(
+        rna_coord,
+        cell_mask,
+        nuc_mask,
+        cell_mask_out_nuc,
+        ndim,
+        voxel_size_yx,
+        check_input=True):
     """Compute topographic features.
 
     Parameters
     ----------
-    rna_coord : np.ndarray, np.int64
+    rna_coord : np.ndarray, np.int
         Coordinates of the detected RNAs with zyx or yx coordinates in the
         first 3 or 2 columns.
     cell_mask : np.ndarray, bool
@@ -717,7 +767,7 @@ def features_topography(rna_coord, cell_mask, nuc_mask, cell_mask_out_nuc,
             voxel_size_yx=(int, float))
         if ndim not in [2, 3]:
             raise ValueError("'ndim' should be 2 or 3, not {0}.".format(ndim))
-        stack.check_array(rna_coord, ndim=2, dtype=np.int64)
+        stack.check_array(rna_coord, ndim=2, dtype=[np.int32, np.int64])
         stack.check_array(cell_mask, ndim=2, dtype=bool)
         stack.check_array(nuc_mask, ndim=2, dtype=bool)
         stack.check_array(cell_mask_out_nuc, ndim=2, dtype=bool)
@@ -807,10 +857,10 @@ def features_foci(rna_coord, foci_coord, ndim, check_input=True):
 
     Parameters
     ----------
-    rna_coord : np.ndarray, np.int64
+    rna_coord : np.ndarray, np.int
         Coordinates of the detected RNAs with zyx or yx coordinates in the
         first 3 or 2 columns.
-    foci_coord : np.ndarray, np.int64
+    foci_coord : np.ndarray, np.int
         Array with shape (nb_foci, 5) or (nb_foci, 4). One coordinate per
         dimension for the foci centroid (zyx or yx coordinates), the number of
         spots detected in the foci and its index.
@@ -831,8 +881,8 @@ def features_foci(rna_coord, foci_coord, ndim, check_input=True):
         stack.check_parameter(ndim=int)
         if ndim not in [2, 3]:
             raise ValueError("'ndim' should be 2 or 3, not {0}.".format(ndim))
-        stack.check_array(rna_coord, ndim=2, dtype=np.int64)
-        stack.check_array(foci_coord, ndim=2, dtype=np.int64)
+        stack.check_array(rna_coord, ndim=2, dtype=[np.int32, np.int64])
+        stack.check_array(foci_coord, ndim=2, dtype=[np.int32, np.int64])
 
     if len(rna_coord) == 0 or len(foci_coord) == 0:
         features = (0.,)
@@ -897,15 +947,21 @@ def features_area(cell_mask, nuc_mask, cell_mask_out_nuc, check_input=True):
     return features
 
 
-def features_centrosome(smfish, rna_coord, distance_centrosome, cell_mask,
-                        ndim, voxel_size_yx, check_input=True):
+def features_centrosome(
+        smfish,
+        rna_coord,
+        distance_centrosome,
+        cell_mask,
+        ndim,
+        voxel_size_yx,
+        check_input=True):
     """Compute centrosome related features (in 2 dimensions).
 
     Parameters
     ----------
     smfish : np.ndarray, np.uint
         Image of RNAs, with shape (y, x).
-    rna_coord : np.ndarray, np.int64
+    rna_coord : np.ndarray, np.int
         Coordinates of the detected RNAs with zyx or yx coordinates in the
         first 3 or 2 columns.
     distance_centrosome : np.ndarray, np.float32
@@ -944,7 +1000,7 @@ def features_centrosome(smfish, rna_coord, distance_centrosome, cell_mask,
         if ndim not in [2, 3]:
             raise ValueError("'ndim' should be 2 or 3, not {0}.".format(ndim))
         stack.check_array(smfish, ndim=2, dtype=[np.uint8, np.uint16])
-        stack.check_array(rna_coord, ndim=2, dtype=np.int64)
+        stack.check_array(rna_coord, ndim=2, dtype=[np.int32, np.int64])
         stack.check_array(
             distance_centrosome,
             ndim=2,
diff --git a/bigfish/classification/input_preparation.py b/bigfish/classification/input_preparation.py
index 514b5b9..e1725e3 100644
--- a/bigfish/classification/input_preparation.py
+++ b/bigfish/classification/input_preparation.py
@@ -16,8 +16,12 @@
 
 # ### Input data ###
 
-def prepare_extracted_data(cell_mask, nuc_mask=None, ndim=None, rna_coord=None,
-                           centrosome_coord=None):
+def prepare_extracted_data(
+        cell_mask,
+        nuc_mask=None,
+        ndim=None,
+        rna_coord=None,
+        centrosome_coord=None):
     """Prepare data extracted from images.
 
     Parameters
@@ -29,12 +33,12 @@ def prepare_extracted_data(cell_mask, nuc_mask=None, ndim=None, rna_coord=None,
     ndim : int
         Number of spatial dimensions to consider (2 or 3). Mandatory if
         `rna_coord` is provided.
-    rna_coord : np.ndarray, np.int64
+    rna_coord : np.ndarray, np.int
         Coordinates of the detected spots with shape (nb_spots, 4) or
         (nb_spots, 3). One coordinate per dimension (zyx or yx dimensions)
         plus the index of the cluster assigned to the spot. If no cluster was
         assigned, value is -1.
-    centrosome_coord : np.ndarray, np.int64
+    centrosome_coord : np.ndarray, np.int
         Coordinates of the detected centrosome with shape (nb_elements, 3) or
         (nb_elements, 2). One coordinate per dimension (zyx or yx dimensions).
 
@@ -46,7 +50,7 @@ def prepare_extracted_data(cell_mask, nuc_mask=None, ndim=None, rna_coord=None,
         Distance map from the cell with shape (y, x), in pixels.
     distance_cell_normalized : np.ndarray, np.float32
         Normalized distance map from the cell with shape (y, x).
-    centroid_cell : np.ndarray, np.int64
+    centroid_cell : np.ndarray, np.int
         Coordinates of the cell centroid with shape (2,).
     distance_centroid_cell : np.ndarray, np.float32
         Distance map from the cell centroid with shape (y, x), in pixels.
@@ -58,20 +62,20 @@ def prepare_extracted_data(cell_mask, nuc_mask=None, ndim=None, rna_coord=None,
         Distance map from the nucleus with shape (y, x), in pixels.
     distance_nuc_normalized : np.ndarray, np.float32
         Normalized distance map from the nucleus with shape (y, x).
-    centroid_nuc : np.ndarray, np.int64
+    centroid_nuc : np.ndarray, np.int
         Coordinates of the nucleus centroid with shape (2,).
     distance_centroid_nuc : np.ndarray, np.float32
         Distance map from the nucleus centroid with shape (y, x), in pixels.
-    rna_coord_out_nuc : np.ndarray, np.int64
+    rna_coord_out_nuc : np.ndarray, np.int
         Coordinates of the detected spots with shape (nb_spots, 4) or
         (nb_spots, 3). One coordinate per dimension (zyx or yx dimensions)
         plus the index of the cluster assigned to the spot. If no cluster was
         assigned, value is -1. Spots detected inside the nucleus are removed.
-    centroid_rna : np.ndarray, np.int64
+    centroid_rna : np.ndarray, np.int
         Coordinates of the rna centroid with shape (2,) or (3,).
     distance_centroid_rna : np.ndarray, np.float32
         Distance map from the rna centroid with shape (y, x), in pixels.
-    centroid_rna_out_nuc : np.ndarray, np.int64
+    centroid_rna_out_nuc : np.ndarray, np.int
         Coordinates of the rna centroid (outside the nucleus) with shape (2,)
         or (3,).
     distance_centroid_rna_out_nuc : np.ndarray, np.float32
@@ -81,7 +85,6 @@ def prepare_extracted_data(cell_mask, nuc_mask=None, ndim=None, rna_coord=None,
         Distance map from the centrosome with shape (y, x), in pixels.
 
     """
-    # TODO allow RNA coordinates in float64 and int64
     # check parameters
     stack.check_parameter(ndim=(int, type(None)))
     if rna_coord is not None and ndim is None:
@@ -91,18 +94,24 @@ def prepare_extracted_data(cell_mask, nuc_mask=None, ndim=None, rna_coord=None,
     stack.check_array(
         cell_mask,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64, bool])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
     cell_mask = cell_mask.astype(bool)
     if nuc_mask is not None:
         stack.check_array(
             nuc_mask,
             ndim=2,
-            dtype=[np.uint8, np.uint16, np.int64, bool])
+            dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
         nuc_mask = nuc_mask.astype(bool)
     if rna_coord is not None:
-        stack.check_array(rna_coord, ndim=2, dtype=np.int64)
+        stack.check_array(
+            rna_coord,
+            ndim=2,
+            dtype=[np.int32, np.int64])
     if centrosome_coord is not None:
-        stack.check_array(centrosome_coord, ndim=2, dtype=np.int64)
+        stack.check_array(
+            centrosome_coord,
+            ndim=2,
+            dtype=[np.int32, np.int64])
 
     # build distance map from the cell boundaries
     distance_cell = ndi.distance_transform_edt(cell_mask)
@@ -110,7 +119,7 @@ def prepare_extracted_data(cell_mask, nuc_mask=None, ndim=None, rna_coord=None,
     distance_cell_normalized = distance_cell / distance_cell.max()
 
     # get cell centroid and a distance map from its localisation
-    centroid_cell = _get_centroid_surface(cell_mask)
+    centroid_cell = _get_centroid_surface(cell_mask).astype(rna_coord.dtype)
     distance_centroid_cell = _get_centroid_distance_map(
         centroid_cell,
         cell_mask)
@@ -129,7 +138,7 @@ def prepare_extracted_data(cell_mask, nuc_mask=None, ndim=None, rna_coord=None,
         distance_nuc_normalized = distance_nuc / distance_nuc.max()
 
         # get nucleus centroid and a distance map from its localisation
-        centroid_nuc = _get_centroid_surface(nuc_mask)
+        centroid_nuc = _get_centroid_surface(nuc_mask).astype(rna_coord.dtype)
         distance_centroid_nuc = _get_centroid_distance_map(
             centroid_nuc,
             cell_mask)
@@ -146,7 +155,7 @@ def prepare_extracted_data(cell_mask, nuc_mask=None, ndim=None, rna_coord=None,
 
         # get rna centroid
         if len(rna_coord) == 0:
-            centroid_rna = np.array([0] * ndim, dtype=np.int64)
+            centroid_rna = np.array([0] * ndim, dtype=rna_coord.dtype)
         else:
             centroid_rna = _get_centroid_rna(rna_coord, ndim)
 
@@ -164,7 +173,8 @@ def prepare_extracted_data(cell_mask, nuc_mask=None, ndim=None, rna_coord=None,
 
             # get rna centroid (outside nucleus)
             if len(rna_coord_out_nuc) == 0:
-                centroid_rna_out_nuc = np.array([0] * ndim, dtype=np.int64)
+                centroid_rna_out_nuc = np.array(
+                    [0] * ndim, dtype=rna_coord.dtype)
             else:
                 centroid_rna_out_nuc = _get_centroid_rna(
                     rna_coord_out_nuc,
@@ -234,7 +244,7 @@ def _get_centroid_surface(mask):
 
     Returns
     -------
-    centroid : np.ndarray, np.int64
+    centroid : np.ndarray, np.int
         Coordinates of the centroid with shape (2,).
 
     """
@@ -250,7 +260,7 @@ def _get_centroid_rna(rna_coord, ndim):
 
     Parameters
     ----------
-    rna_coord : np.ndarray, np.int64
+    rna_coord : np.ndarray, np.int
         Coordinates of the detected spots with shape (nb_spots, 4) or
         (nb_spots, 3). One coordinate per dimension (zyx or yx dimensions)
         plus the index of the cluster assigned to the spot. If no cluster was
@@ -260,12 +270,12 @@ def _get_centroid_rna(rna_coord, ndim):
 
     Returns
     -------
-    centroid_rna : np.ndarray, np.int64
+    centroid_rna : np.ndarray, np.int
         Coordinates of the rna centroid with shape (2,) or (3,).
 
     """
     # get rna centroids
-    centroid_rna = np.mean(rna_coord[:, :ndim], axis=0, dtype=np.int64)
+    centroid_rna = np.mean(rna_coord[:, :ndim], axis=0, dtype=rna_coord.dtype)
 
     return centroid_rna
 
@@ -275,7 +285,7 @@ def _get_centroid_distance_map(centroid, cell_mask):
 
     Parameters
     ----------
-    centroid : np.ndarray, np.int64
+    centroid : np.ndarray, np.int
         Coordinates of the centroid with shape (2,) or (3,).
     cell_mask : np.ndarray, bool
         Binary surface of the cell with shape (y, x).
@@ -308,7 +318,7 @@ def _get_centrosome_distance_map(centrosome_coord, cell_mask):
 
     Parameters
     ----------
-    centrosome_coord : np.ndarray, np.int64
+    centrosome_coord : np.ndarray, np.int
         Coordinates of the detected centrosome with shape (nb_elements, 3) or
         (nb_elements, 2). One coordinate per dimension (zyx or yx dimensions).
     cell_mask : np.ndarray, bool
diff --git a/bigfish/detection/__init__.py b/bigfish/detection/__init__.py
index d48d7d8..7b90428 100644
--- a/bigfish/detection/__init__.py
+++ b/bigfish/detection/__init__.py
@@ -30,6 +30,8 @@
 from .utils import get_object_radius_pixel
 from .utils import get_object_radius_nm
 from .utils import build_reference_spot
+from .utils import get_spot_volume
+from .utils import get_spot_surface
 from .utils import compute_snr_spots
 from .utils import get_breaking_point
 
@@ -62,6 +64,8 @@
     "get_object_radius_pixel",
     "get_object_radius_nm",
     "build_reference_spot",
+    "get_spot_volume",
+    "get_spot_surface",
     "compute_snr_spots",
     "get_breaking_point"]
 
diff --git a/bigfish/detection/cluster_detection.py b/bigfish/detection/cluster_detection.py
index 92e9487..73aad26 100644
--- a/bigfish/detection/cluster_detection.py
+++ b/bigfish/detection/cluster_detection.py
@@ -58,7 +58,10 @@ def detect_clusters(spots, voxel_size, radius=350, nb_min_spots=4):
     # TODO check that the behavior is the same with float64 and int64
     #  coordinates
     # check parameters
-    stack.check_array(spots, ndim=2, dtype=[np.float64, np.int64])
+    stack.check_array(
+        spots,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
     stack.check_parameter(
         voxel_size=(int, float, tuple, list),
         radius=int,
@@ -158,6 +161,9 @@ def _extract_information(clustered_spots):
         number of spots detected in the cluster and its index.
 
     """
+    # store dtype
+    dtype = clustered_spots.dtype
+
     # extract information for 3-d cluster...
     if clustered_spots.shape[1] == 4:
 
@@ -165,7 +171,7 @@ def _extract_information(clustered_spots):
         labels_clusters = np.unique(
             clustered_spots[clustered_spots[:, 3] != -1, 3])
         if labels_clusters.size == 0:
-            clusters = np.array([], dtype=np.int64).reshape((0, 5))
+            clusters = np.array([], dtype=dtype).reshape((0, 5))
             return clusters
 
         # shape information
@@ -177,7 +183,7 @@ def _extract_information(clustered_spots):
             nb_spots_cluster = len(spots_in_cluster)
             clusters.append([z_cluster, y_cluster, x_cluster,
                              nb_spots_cluster, label])
-        clusters = np.array(clusters, dtype=np.int64)
+        clusters = np.array(clusters, dtype=dtype)
 
     # ... and 2-d cluster
     else:
@@ -186,7 +192,7 @@ def _extract_information(clustered_spots):
         labels_clusters = np.unique(
             clustered_spots[clustered_spots[:, 2] != -1, 2])
         if labels_clusters.size == 0:
-            clusters = np.array([], dtype=np.int64).reshape((0, 4))
+            clusters = np.array([], dtype=dtype).reshape((0, 4))
             return clusters
 
         # shape information
@@ -197,6 +203,6 @@ def _extract_information(clustered_spots):
             y_cluster, x_cluster = spots_in_cluster.mean(axis=0)
             nb_spots_cluster = len(spots_in_cluster)
             clusters.append([y_cluster, x_cluster, nb_spots_cluster, label])
-        clusters = np.array(clusters, dtype=np.int64)
+        clusters = np.array(clusters, dtype=dtype)
 
     return clusters
diff --git a/bigfish/detection/dense_decomposition.py b/bigfish/detection/dense_decomposition.py
index 88054fa..1a15292 100644
--- a/bigfish/detection/dense_decomposition.py
+++ b/bigfish/detection/dense_decomposition.py
@@ -28,8 +28,15 @@
 
 # ### Main function ###
 
-def decompose_dense(image, spots, voxel_size, spot_radius, kernel_size=None,
-                    alpha=0.5, beta=1, gamma=5):
+def decompose_dense(
+        image,
+        spots,
+        voxel_size,
+        spot_radius,
+        kernel_size=None,
+        alpha=0.5,
+        beta=1,
+        gamma=5):
     """Detect dense and bright regions with potential clustered spots and
     simulate a more realistic number of spots in these regions.
 
@@ -44,7 +51,7 @@ def decompose_dense(image, spots, voxel_size, spot_radius, kernel_size=None,
     ----------
     image : np.ndarray
         Image with shape (z, y, x) or (y, x).
-    spots : np.ndarray, np.int64
+    spots : np.ndarray
         Coordinate of the spots with shape (nb_spots, 3) or (nb_spots, 2)
         for 3-d or 2-d images respectively.
     voxel_size : int, float, Tuple(int, float) or List(int, float)
@@ -93,7 +100,7 @@ def decompose_dense(image, spots, voxel_size, spot_radius, kernel_size=None,
 
     Returns
     -------
-    spots : np.ndarray, np.int64
+    spots : np.ndarray
         Coordinate of the spots detected, with shape (nb_spots, 3) or
         (nb_spots, 2). One coordinate per dimension (zyx or yx coordinates).
     dense_regions : np.ndarray, np.int64
@@ -105,13 +112,15 @@ def decompose_dense(image, spots, voxel_size, spot_radius, kernel_size=None,
         Reference spot in 3-d or 2-d.
 
     """
-    # TODO allow/return float64 spots
     # check parameters
     stack.check_array(
         image,
         ndim=[2, 3],
         dtype=[np.uint8, np.uint16, np.float32, np.float64])
-    stack.check_array(spots, ndim=2, dtype=np.int64)
+    stack.check_array(
+        spots,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
     stack.check_parameter(
         voxel_size=(int, float, tuple, list),
         spot_radius=(int, float, tuple, list),
@@ -129,6 +138,9 @@ def decompose_dense(image, spots, voxel_size, spot_radius, kernel_size=None,
         raise ValueError("'gamma' should be a positive value, not {0}"
                          .format(gamma))
 
+    # store spots dtype
+    dtype = spots.dtype
+
     # check consistency between parameters
     ndim = image.ndim
     if ndim != spots.shape[1]:
@@ -158,7 +170,7 @@ def decompose_dense(image, spots, voxel_size, spot_radius, kernel_size=None,
 
     # case where no spot were detected
     if spots.size == 0:
-        dense_regions = np.array([], dtype=np.int64).reshape((0, ndim + 4))
+        dense_regions = np.array([], dtype=dtype).reshape((0, ndim + 4))
         reference_spot = np.zeros((5,) * ndim, dtype=image.dtype)
         return spots, dense_regions, reference_spot
 
@@ -189,7 +201,7 @@ def decompose_dense(image, spots, voxel_size, spot_radius, kernel_size=None,
 
     # case with an empty frame as reference spot
     if reference_spot.sum() == 0:
-        dense_regions = np.array([], dtype=np.int64).reshape((0, ndim + 4))
+        dense_regions = np.array([], dtype=dtype).reshape((0, ndim + 4))
         return spots, dense_regions, reference_spot
 
     # fit a gaussian function on the reference spot to be able to simulate it
@@ -214,7 +226,7 @@ def decompose_dense(image, spots, voxel_size, spot_radius, kernel_size=None,
 
     # case where no region where detected
     if regions_to_decompose.size == 0:
-        dense_regions = np.array([], dtype=np.int64).reshape((0, ndim + 4))
+        dense_regions = np.array([], dtype=dtype).reshape((0, ndim + 4))
         return spots, dense_regions, reference_spot
 
     # precompute gaussian function values
@@ -234,6 +246,7 @@ def decompose_dense(image, spots, voxel_size, spot_radius, kernel_size=None,
         amplitude=amplitude,
         background=background,
         precomputed_gaussian=precomputed_gaussian)
+    spots_in_regions = spots_in_regions.astype(dtype)
 
     # normally the number of detected spots should increase
     if len(spots_out_regions) + len(spots_in_regions) < len(spots):
@@ -261,7 +274,7 @@ def get_dense_region(image, spots, voxel_size, spot_radius, beta=1):
     ----------
     image : np.ndarray
         Image with shape (z, y, x) or (y, x).
-    spots : np.ndarray, np.int64
+    spots : np.ndarray
         Coordinate of the spots with shape (nb_spots, 3) or (nb_spots, 2).
     voxel_size : int, float, Tuple(int, float) or List(int, float)
         Size of a voxel, in nanometer. One value per spatial dimension (zyx or
@@ -286,7 +299,7 @@ def get_dense_region(image, spots, voxel_size, spot_radius, beta=1):
     dense_regions : np.ndarray
         Array with selected ``skimage.measure._regionprops._RegionProperties``
         objects.
-    spots_out_region : np.ndarray, np.int64
+    spots_out_region : np.ndarray
         Coordinate of the spots detected out of dense regions, with shape
         (nb_spots, 3) or (nb_spots, 2). One coordinate per dimension (zyx or
         yx coordinates).
@@ -294,13 +307,15 @@ def get_dense_region(image, spots, voxel_size, spot_radius, beta=1):
         Maximum size of the regions.
 
     """
-    # TODO allow/return float64 spots
     # check parameters
     stack.check_array(
         image,
         ndim=[2, 3],
         dtype=[np.uint8, np.uint16, np.float32, np.float64])
-    stack.check_array(spots, ndim=2, dtype=np.int64)
+    stack.check_array(
+        spots,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
     stack.check_parameter(
         voxel_size=(int, float, tuple, list),
         spot_radius=(int, float, tuple, list),
@@ -387,14 +402,14 @@ def _filter_connected_region(image, connected_component, spots):
         Image with shape (z, y, x) or (y, x).
     connected_component : np.ndarray, np.int64
         Image labelled with shape (z, y, x) or (y, x).
-    spots : np.ndarray, np.int64
+    spots : np.ndarray
         Coordinate of the spots with shape (nb_spots, 3) or (nb_spots, 2).
 
     Returns
     -------
     regions_filtered : np.ndarray
         Array with filtered skimage.measure._regionprops._RegionProperties.
-    spots_out_region : np.ndarray, np.int64
+    spots_out_region : np.ndarray
         Coordinate of the spots outside the regions with shape (nb_spots, 3)
         or (nb_spots, 2).
     max_region_size : int
@@ -437,14 +452,14 @@ def _filter_spot_out_candidate_regions(candidate_bbox, spots, nb_dim):
     ----------
     candidate_bbox : List[Tuple]
         List of Tuples with the bounding box coordinates.
-    spots : np.ndarray, np.int64
+    spots : np.ndarray
         Coordinate of the spots with shape (nb_spots, 3) or (nb_spots, 2).
     nb_dim : int
         Number of dimensions to consider (2 or 3).
 
     Returns
     -------
-    spots_out_region : np.ndarray, np.int64
+    spots_out_region : np.ndarray
         Coordinate of the spots outside the regions with shape (nb_spots, 3)
         or (nb_spots, 2).
     max_region_size : int
@@ -501,9 +516,14 @@ def _filter_spot_out_candidate_regions(candidate_bbox, spots, nb_dim):
 
 # ### Gaussian simulation ###
 
-def simulate_gaussian_mixture(image, candidate_regions, voxel_size, sigma,
-                              amplitude=100, background=0,
-                              precomputed_gaussian=None):
+def simulate_gaussian_mixture(
+        image,
+        candidate_regions,
+        voxel_size,
+        sigma,
+        amplitude=100,
+        background=0,
+        precomputed_gaussian=None):
     """Simulate as many gaussians as possible in the candidate dense regions in
     order to get a more realistic number of spots.
 
@@ -542,7 +562,6 @@ def simulate_gaussian_mixture(image, candidate_regions, voxel_size, sigma,
         average intensity value and its index.
 
     """
-    # TODO allow/return float64 spots
     # check parameters
     stack.check_array(
         image,
@@ -643,14 +662,23 @@ def simulate_gaussian_mixture(image, candidate_regions, voxel_size, sigma,
                             region_area, region_intensity, i_region])
 
     spots_in_regions = np.concatenate(spots_in_regions, axis=0)
+    spots_in_regions = spots_in_regions.astype(np.int64)
     regions = np.array(regions, dtype=np.int64)
 
     return spots_in_regions, regions
 
 
-def _gaussian_mixture_3d(image, region, voxel_size_z, voxel_size_yx, sigma_z,
-                         sigma_yx, amplitude, background, precomputed_gaussian,
-                         limit_gaussian=1000):
+def _gaussian_mixture_3d(
+        image,
+        region,
+        voxel_size_z,
+        voxel_size_yx,
+        sigma_z,
+        sigma_yx,
+        amplitude,
+        background,
+        precomputed_gaussian,
+        limit_gaussian=1000):
     """Fit as many 3-d gaussians as possible in a candidate region.
 
     Parameters
@@ -749,9 +777,15 @@ def _gaussian_mixture_3d(image, region, voxel_size_z, voxel_size_yx, sigma_z,
     return image_region, best_simulation, positions_gaussian
 
 
-def _gaussian_mixture_2d(image, region, voxel_size_yx, sigma_yx, amplitude,
-                         background, precomputed_gaussian,
-                         limit_gaussian=1000):
+def _gaussian_mixture_2d(
+        image,
+        region,
+        voxel_size_yx,
+        sigma_yx,
+        amplitude,
+        background,
+        precomputed_gaussian,
+        limit_gaussian=1000):
     """Fit as many 2-d gaussians as possible in a candidate region.
 
     Parameters
diff --git a/bigfish/detection/spot_detection.py b/bigfish/detection/spot_detection.py
index 30c6ccb..1d1ed90 100644
--- a/bigfish/detection/spot_detection.py
+++ b/bigfish/detection/spot_detection.py
@@ -22,9 +22,15 @@
 
 # ### Main function ###
 
-def detect_spots(images, threshold=None, remove_duplicate=True,
-                 return_threshold=False, voxel_size=None, spot_radius=None,
-                 log_kernel_size=None, minimum_distance=None):
+def detect_spots(
+        images,
+        threshold=None,
+        remove_duplicate=True,
+        return_threshold=False,
+        voxel_size=None,
+        spot_radius=None,
+        log_kernel_size=None,
+        minimum_distance=None):
     """Apply LoG filter followed by a Local Maximum algorithm to detect spots
     in a 2-d or 3-d image.
 
@@ -209,9 +215,13 @@ def detect_spots(images, threshold=None, remove_duplicate=True,
         return spots
 
 
-def _detect_spots_from_images(images, threshold=None, remove_duplicate=True,
-                              return_threshold=False, log_kernel_size=None,
-                              min_distance=None):
+def _detect_spots_from_images(
+        images,
+        threshold=None,
+        remove_duplicate=True,
+        return_threshold=False,
+        log_kernel_size=None,
+        min_distance=None):
     """Apply LoG filter followed by a Local Maximum algorithm to detect spots
     in a 2-d or 3-d image.
 
@@ -311,8 +321,8 @@ def _detect_spots_from_images(images, threshold=None, remove_duplicate=True,
         mask_local_max = masks[i]
 
         # detection
-        spots, _ = spots_thresholding(image_filtered, mask_local_max,
-                                      threshold, remove_duplicate)
+        spots, _ = spots_thresholding(
+            image_filtered, mask_local_max, threshold, remove_duplicate)
         all_spots.append(spots)
 
     # return threshold or not
@@ -382,8 +392,11 @@ def local_maximum_detection(image, min_distance):
     return mask
 
 
-def spots_thresholding(image, mask_local_max, threshold,
-                       remove_duplicate=True):
+def spots_thresholding(
+        image,
+        mask_local_max,
+        threshold,
+        remove_duplicate=True):
     """Filter detected spots and get coordinates of the remaining spots.
 
     In order to make the thresholding robust, it should be applied to a
@@ -422,7 +435,7 @@ def spots_thresholding(image, mask_local_max, threshold,
     stack.check_array(
         mask_local_max,
         ndim=[2, 3],
-        dtype=[bool])
+        dtype=bool)
     stack.check_parameter(
         threshold=(float, int, type(None)),
         remove_duplicate=bool)
@@ -499,7 +512,10 @@ def automated_threshold_setting(image, mask_local_max):
         image,
         ndim=[2, 3],
         dtype=[np.uint8, np.uint16, np.float32, np.float64])
-    stack.check_array(mask_local_max, ndim=[2, 3], dtype=[bool])
+    stack.check_array(
+        mask_local_max,
+        ndim=[2, 3],
+        dtype=bool)
 
     # get threshold values we want to test
     thresholds = _get_candidate_thresholds(image.ravel())
@@ -578,8 +594,12 @@ def _get_spot_counts(thresholds, value_spots):
     return thresholds, count_spots
 
 
-def get_elbow_values(images, voxel_size=None, spot_radius=None,
-                     log_kernel_size=None, minimum_distance=None):
+def get_elbow_values(
+        images,
+        voxel_size=None,
+        spot_radius=None,
+        log_kernel_size=None,
+        minimum_distance=None):
     """Get values to plot the elbow curve used to automatically set the
     threshold to detect spots.
 
diff --git a/bigfish/detection/spot_modeling.py b/bigfish/detection/spot_modeling.py
index 43ef9c4..d851974 100644
--- a/bigfish/detection/spot_modeling.py
+++ b/bigfish/detection/spot_modeling.py
@@ -10,8 +10,8 @@
 
 import bigfish.stack as stack
 
-from .utils import _get_spot_volume
-from .utils import _get_spot_surface
+from .utils import get_spot_volume
+from .utils import get_spot_surface
 from .utils import get_object_radius_pixel
 
 from scipy.special import erf
@@ -215,8 +215,11 @@ def initialize_grid(image_spot, voxel_size, return_centroid=False):
             return grid
 
 
-def _initialize_grid_3d(image_spot, voxel_size_z, voxel_size_yx,
-                        return_centroid=False):
+def _initialize_grid_3d(
+        image_spot,
+        voxel_size_z,
+        voxel_size_yx,
+        return_centroid=False):
     """Build a grid in nanometer to compute gaussian function values over a
     full volume.
 
@@ -351,8 +354,7 @@ def _initialize_background_amplitude(image_spot):
 
 # ### Pixel fitting ###
 
-def _objective_function(ndim, voxel_size, sigma_z, sigma_yx,
-                        amplitude):
+def _objective_function(ndim, voxel_size, sigma_z, sigma_yx, amplitude):
     """Design the objective function used to fit the gaussian function.
 
     Parameters
@@ -393,8 +395,12 @@ def _objective_function(ndim, voxel_size, sigma_z, sigma_yx,
     return f
 
 
-def _objective_function_3d(voxel_size_z, voxel_size_yx, sigma_z, sigma_yx,
-                           amplitude):
+def _objective_function_3d(
+        voxel_size_z,
+        voxel_size_yx,
+        sigma_z,
+        sigma_yx,
+        amplitude):
     """Design the objective function used to fit the gaussian function.
 
     Parameters
@@ -497,9 +503,18 @@ def f(grid, mu_z, mu_y, mu_x, sigma_z, sigma_yx, amplitude,
 
 
 # TODO add equations in the docstring
-def gaussian_3d(grid, mu_z, mu_y, mu_x, sigma_z, sigma_yx, voxel_size_z,
-                voxel_size_yx, amplitude, background,
-                precomputed=None):
+def gaussian_3d(
+        grid,
+        mu_z,
+        mu_y,
+        mu_x,
+        sigma_z,
+        sigma_yx,
+        voxel_size_z,
+        voxel_size_yx,
+        amplitude,
+        background,
+        precomputed=None):
     """Compute the gaussian function over the grid representing a volume V
     with shape (V_z, V_y, V_x).
 
@@ -668,8 +683,15 @@ def f(grid, mu_y, mu_x, sigma_yx, amplitude, background):
 
 
 # TODO add equations in the docstring
-def gaussian_2d(grid, mu_y, mu_x, sigma_yx, voxel_size_yx, amplitude,
-                background, precomputed=None):
+def gaussian_2d(
+        grid,
+        mu_y,
+        mu_x,
+        sigma_yx,
+        voxel_size_yx,
+        amplitude,
+        background,
+        precomputed=None):
     """Compute the gaussian function over the grid representing a surface S
     with shape (S_y, S_x).
 
@@ -747,11 +769,10 @@ def gaussian_2d(grid, mu_y, mu_x, sigma_yx, voxel_size_yx, amplitude,
     return values
 
 
+# TODO add equations in the docstring
 def _rescaled_erf(low, high, mu, sigma):
     """Rescaled the Error function along a specific axis.
 
-    # TODO add equations
-
     Parameters
     ----------
     low : np.ndarray, np.float
@@ -778,11 +799,10 @@ def _rescaled_erf(low, high, mu, sigma):
     return rescaled_erf
 
 
+# TODO add equations and optimization algorithm in the docstring
 def _fit_gaussian(f, grid, image_spot, p0, lower_bound=None, upper_bound=None):
     """Fit a gaussian function to a 3-d or 2-d image.
 
-    # TODO add equations and algorithm
-
     Parameters
     ----------
     f : func
@@ -810,7 +830,6 @@ def _fit_gaussian(f, grid, image_spot, p0, lower_bound=None, upper_bound=None):
     """
     # TODO check that we do not fit a 2-d gaussian function to a 3-d image or
     #  the opposite
-
     # compute lower bound and upper bound
     if lower_bound is None:
         lower_bound = [-np.inf for _ in p0]
@@ -939,7 +958,7 @@ def fit_subpixel(image, spots, voxel_size, spot_radius):
 
     Returns
     -------
-    spots_subpixel : np.ndarray, np.float64
+    spots_subpixel : np.ndarray
         Coordinate of the spots detected, with shape (nb_spots, 3) or
         (nb_spots, 2). One coordinate per dimension (zyx or yx coordinates).
 
@@ -949,7 +968,10 @@ def fit_subpixel(image, spots, voxel_size, spot_radius):
         image,
         ndim=[2, 3],
         dtype=[np.uint8, np.uint16, np.float32, np.float64])
-    stack.check_array(spots, ndim=2, dtype=[np.float64, np.int64])
+    stack.check_array(
+        spots,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
     stack.check_parameter(
         voxel_size=(int, float, tuple, list),
         spot_radius=(int, float, tuple, list))
@@ -1006,19 +1028,29 @@ def fit_subpixel(image, spots, voxel_size, spot_radius):
 
     # format results
     spots_subpixel = np.stack(spots_subpixel)
+    if spots.dtype == np.float32:
+        spots_subpixel = spots_subpixel.astype(np.float32)
+    else:
+        spots_subpixel = spots_subpixel.astype(np.float64)
 
     return spots_subpixel
 
 
-def _fit_subpixel_3d(image, coord, radius_to_crop, voxel_size_z, voxel_size_yx,
-                     spot_radius_z, spot_radius_yx):
+def _fit_subpixel_3d(
+        image,
+        coord,
+        radius_to_crop,
+        voxel_size_z,
+        voxel_size_yx,
+        spot_radius_z,
+        spot_radius_yx):
     """Fit a 3-d gaussian on a detected spot.
 
     Parameters
     ----------
     image : np.ndarray
         Image with shape (z, y, x).
-    coord : np.ndarray, np.int64
+    coord : np.ndarray
         Coordinate of the spot detected, with shape (3,). One coordinate per
         dimension (zyx coordinates).
     radius_to_crop : Tuple[float]
@@ -1041,7 +1073,7 @@ def _fit_subpixel_3d(image, coord, radius_to_crop, voxel_size_z, voxel_size_yx,
 
     """
     # extract spot image
-    image_spot, bbox_low = _get_spot_volume(
+    image_spot, bbox_low = get_spot_volume(
         image=image,
         spot_z=coord[0],
         spot_y=coord[1],
@@ -1083,15 +1115,19 @@ def _fit_subpixel_3d(image, coord, radius_to_crop, voxel_size_z, voxel_size_yx,
     return new_coord
 
 
-def _fit_subpixel_2d(image, coord, radius_to_crop, voxel_size_yx,
-                     spot_radius_yx):
+def _fit_subpixel_2d(
+        image,
+        coord,
+        radius_to_crop,
+        voxel_size_yx,
+        spot_radius_yx):
     """Fit a 2-d gaussian on a detected spot.
 
     Parameters
     ----------
     image : np.ndarray
         Image with shape (y, x).
-    coord : np.ndarray, np.int64
+    coord : np.ndarray
         Coordinate of the spot detected, with shape (2,). One coordinate per
         dimension (yx coordinates).
     radius_to_crop : Tuple[float]
@@ -1110,7 +1146,7 @@ def _fit_subpixel_2d(image, coord, radius_to_crop, voxel_size_yx,
 
     """
     # extract spot image
-    image_spot, bbox_low = _get_spot_surface(
+    image_spot, bbox_low = get_spot_surface(
         image=image,
         spot_y=coord[0],
         spot_x=coord[1],
diff --git a/bigfish/detection/utils.py b/bigfish/detection/utils.py
index 919bee1..c921a86 100644
--- a/bigfish/detection/utils.py
+++ b/bigfish/detection/utils.py
@@ -37,7 +37,10 @@ def convert_spot_coordinates(spots, voxel_size):
     """
     # check parameters
     stack.check_parameter(voxel_size=(int, float, tuple, list))
-    stack.check_array(spots, ndim=2, dtype=[np.float64, np.int64])
+    stack.check_array(
+        spots,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
     dtype = spots.dtype
 
     # check consistency between parameters
@@ -211,7 +214,10 @@ def build_reference_spot(image, spots, voxel_size, spot_radius, alpha=0.5):
         image,
         ndim=[2, 3],
         dtype=[np.uint8, np.uint16, np.float32, np.float64])
-    stack.check_array(spots, ndim=2, dtype=[np.float64, np.int64])
+    stack.check_array(
+        spots,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
     stack.check_parameter(
         voxel_size=(int, float, tuple, list),
         spot_radius=(int, float, tuple, list),
@@ -303,8 +309,8 @@ def _build_reference_spot_3d(image, spots, radius, alpha):
         spot_z, spot_y, spot_x = candidate_spots[i_spot, :]
 
         # get the volume of the spot
-        image_spot, _, = _get_spot_volume(image, spot_z, spot_y, spot_x,
-                                          radius_z, radius_yx)
+        image_spot, _, = get_spot_volume(
+            image, spot_z, spot_y, spot_x, radius_z, radius_yx)
 
         # keep images that are not cropped by the borders
         if image_spot.shape == (z_shape, yx_shape, yx_shape):
@@ -329,22 +335,22 @@ def _build_reference_spot_3d(image, spots, radius, alpha):
     return reference_spot
 
 
-def _get_spot_volume(image, spot_z, spot_y, spot_x, radius_z, radius_yx):
+def get_spot_volume(image, spot_z, spot_y, spot_x, radius_z, radius_yx):
     """Get a subimage of a detected spot in 3 dimensions.
 
     Parameters
     ----------
     image : np.ndarray
         Image with shape (z, y, x).
-    spot_z : np.int64
+    spot_z : int or float
         Coordinate of the detected spot along the z axis.
-    spot_y : np.int64
+    spot_y : int or float
         Coordinate of the detected spot along the y axis.
-    spot_x : np.int64
+    spot_x : int or float
         Coordinate of the detected spot along the x axis.
-    radius_z : int
+    radius_z : int or float
         Radius in pixel of the detected spot, along the z axis.
-    radius_yx : int
+    radius_yx : int or float
         Radius in pixel of the detected spot, on the yx plan.
 
     Returns
@@ -414,7 +420,7 @@ def _build_reference_spot_2d(image, spots, radius, alpha):
         spot_y, spot_x = candidate_spots[i_spot, :]
 
         # get the volume of the spot
-        image_spot, _ = _get_spot_surface(image, spot_y, spot_x, radius_yx)
+        image_spot, _ = get_spot_surface(image, spot_y, spot_x, radius_yx)
 
         # keep images that are not cropped by the borders
         if image_spot.shape == (yx_shape, yx_shape):
@@ -438,18 +444,18 @@ def _build_reference_spot_2d(image, spots, radius, alpha):
     return reference_spot
 
 
-def _get_spot_surface(image, spot_y, spot_x, radius_yx):
+def get_spot_surface(image, spot_y, spot_x, radius_yx):
     """Get a subimage of a detected spot in 2 dimensions.
 
     Parameters
     ----------
     image : np.ndarray
         Image with shape (y, x).
-    spot_y : np.int64
+    spot_y : int or float
         Coordinate of the detected spot along the y axis.
-    spot_x : np.int64
+    spot_x : int or float
         Coordinate of the detected spot along the x axis.
-    radius_yx : int
+    radius_yx : int or float
         Radius in pixel of the detected spot, on the yx plan.
 
     Returns
@@ -516,7 +522,10 @@ def compute_snr_spots(image, spots, voxel_size, spot_radius):
         ndim=[2, 3],
         dtype=[np.uint8, np.uint16, np.float32, np.float64])
     stack.check_range_value(image, min_=0)
-    stack.check_array(spots, ndim=2, dtype=[np.float64, np.int64])
+    stack.check_array(
+        spots,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
     stack.check_parameter(
         voxel_size=(int, float, tuple, list),
         spot_radius=(int, float, tuple, list))
@@ -587,7 +596,7 @@ def compute_snr_spots(image, spots, voxel_size, spot_radius):
             spot_z = spot[0]
             radius_background_z = radius_background[0]
             max_signal = image_to_process[spot_z, spot_y, spot_x]
-            spot_background_, _ = _get_spot_volume(
+            spot_background_, _ = get_spot_volume(
                 image_to_process, spot_z, spot_y, spot_x,
                 radius_background_z, radius_background_yx)
             spot_background = spot_background_.copy()
@@ -606,7 +615,7 @@ def compute_snr_spots(image, spots, voxel_size, spot_radius):
 
         else:
             max_signal = image_to_process[spot_y, spot_x]
-            spot_background_, _ = _get_spot_surface(
+            spot_background_, _ = get_spot_surface(
                 image_to_process, spot_y, spot_x, radius_background_yx)
             spot_background = spot_background_.copy()
 
@@ -665,8 +674,14 @@ def get_breaking_point(x, y):
 
     """
     # check parameters
-    stack.check_array(x, ndim=1, dtype=[np.float64, np.int64])
-    stack.check_array(y, ndim=1, dtype=[np.float64, np.int64])
+    stack.check_array(
+        x,
+        ndim=1,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
+    stack.check_array(
+        y,
+        ndim=1,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
 
     # select threshold where curve break
     slope = (y[-1] - y[0]) / len(y)
diff --git a/bigfish/multistack/colocalization.py b/bigfish/multistack/colocalization.py
index b2ae091..2ec570b 100644
--- a/bigfish/multistack/colocalization.py
+++ b/bigfish/multistack/colocalization.py
@@ -20,8 +20,13 @@
 
 # ### Main function ###
 
-def detect_spots_colocalization(spots_1, spots_2, voxel_size, threshold=None,
-                                return_indices=False, return_threshold=False):
+def detect_spots_colocalization(
+        spots_1,
+        spots_2,
+        voxel_size,
+        threshold=None,
+        return_indices=False,
+        return_threshold=False):
     """Detect colocalized spots between two arrays of spot coordinates
     'spots_1' and 'spots_2'. Pairs of spots below a specific threshold are
     defined as colocalized.
@@ -76,8 +81,14 @@ def detect_spots_colocalization(spots_1, spots_2, voxel_size, threshold=None,
         return_threshold=bool)
 
     # check spots coordinates
-    stack.check_array(spots_1, ndim=2, dtype=[np.float64, np.int64])
-    stack.check_array(spots_2, ndim=2, dtype=[np.float64, np.int64])
+    stack.check_array(
+        spots_1,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
+    stack.check_array(
+        spots_2,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
 
     # convert spots coordinates in nanometer
     spots_1_nanometer = detection.convert_spot_coordinates(
@@ -194,8 +205,14 @@ def get_elbow_value_colocalized(spots_1, spots_2, voxel_size):
     """
     # check parameters
     stack.check_parameter(voxel_size=(int, float, tuple, list))
-    stack.check_array(spots_1, ndim=2, dtype=[np.float64, np.int64])
-    stack.check_array(spots_2, ndim=2, dtype=[np.float64, np.int64])
+    stack.check_array(
+        spots_1,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
+    stack.check_array(
+        spots_2,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
 
     # check consistency between parameters
     ndim = spots_1.shape[1]
diff --git a/bigfish/multistack/postprocess.py b/bigfish/multistack/postprocess.py
index 27786f0..b550c40 100644
--- a/bigfish/multistack/postprocess.py
+++ b/bigfish/multistack/postprocess.py
@@ -48,8 +48,11 @@ def identify_objects_in_region(mask, coord, ndim):
     stack.check_array(
         mask,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64, bool])
-    stack.check_array(coord, ndim=2, dtype=[np.int64, np.float64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
+    stack.check_array(
+        coord,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
 
     # check number of dimensions
     if ndim not in [2, 3]:
@@ -66,7 +69,7 @@ def identify_objects_in_region(mask, coord, ndim):
         mask = mask.astype(bool)
 
     # cast coordinates dtype if necessary
-    if coord.dtype == np.int64:
+    if coord.dtype in [np.int32, np.int64]:
         coord_int = coord
     else:
         coord_int = np.round(coord).astype(np.int64)
@@ -119,7 +122,10 @@ def remove_transcription_site(rna, clusters, nuc_mask, ndim):
 
     """
     # check parameters
-    stack.check_array(rna, ndim=2, dtype=[np.int64, np.float64])
+    stack.check_array(
+        rna,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
 
     # discriminate foci from transcription sites
     ts, foci = identify_objects_in_region(
@@ -161,11 +167,11 @@ def match_nuc_cell(nuc_label, cell_label, single_nuc, cell_alone):
     stack.check_array(
         nuc_label,
         ndim=[2, 3],
-        dtype=[np.uint8, np.uint16, np.int64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64])
     stack.check_array(
         cell_label,
         ndim=[2, 3],
-        dtype=[np.uint8, np.uint16, np.int64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64])
 
     # initialize new labelled images
     new_nuc_label = np.zeros_like(nuc_label)
@@ -252,9 +258,16 @@ def _get_most_frequent_value(array):
 
 # ### Cell extraction ###
 
-def extract_cell(cell_label, ndim, nuc_label=None, rna_coord=None,
-                 others_coord=None, image=None, others_image=None,
-                 remove_cropped_cell=True, check_nuc_in_cell=True):
+def extract_cell(
+        cell_label,
+        ndim,
+        nuc_label=None,
+        rna_coord=None,
+        others_coord=None,
+        image=None,
+        others_image=None,
+        remove_cropped_cell=True,
+        check_nuc_in_cell=True):
     """Extract cell-level results for an image.
 
     The function gathers different segmentation and detection results obtained
@@ -315,14 +328,17 @@ def extract_cell(cell_label, ndim, nuc_label=None, rna_coord=None,
     stack.check_array(
         cell_label,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64])
     if nuc_label is not None:
         stack.check_array(
             nuc_label,
             ndim=2,
-            dtype=[np.uint8, np.uint16, np.int64])
+            dtype=[np.uint8, np.uint16, np.int32, np.int64])
     if rna_coord is not None:
-        stack.check_array(rna_coord, ndim=2, dtype=[np.int64, np.float64])
+        stack.check_array(
+            rna_coord,
+            ndim=2,
+            dtype=[np.float32, np.float64, np.int32, np.int64])
     if image is not None:
         stack.check_array(image, ndim=2, dtype=[np.uint8, np.uint16])
     actual_keys = ["cell_id", "bbox", "cell_coord", "cell_mask", "nuc_coord",
@@ -335,16 +351,17 @@ def extract_cell(cell_label, ndim, nuc_label=None, rna_coord=None,
             else:
                 actual_keys.append(key)
             array = others_coord[key]
-            stack.check_array(array, ndim=2, dtype=[np.int64, np.float64])
+            stack.check_array(
+                array,
+                ndim=2,
+                dtype=[np.float32, np.float64, np.int32, np.int64])
             if array.shape[1] < ndim:
                 warnings.warn("Array in 'others_coord' have less coordinates "
                               "({0}) than the minimum number of spatial "
                               "dimension we consider ({1})."
                               .format(array.shape[1], ndim),
                               UserWarning)
-    # TODO allow boolean for 'others_image'
-    # TODO bug if 'image' is None but not 'others_image'
-    if others_image is not None:
+    if others_image is not None and image is not None:
         for key in others_image:
             if key in actual_keys:
                 raise KeyError("Key {0} in 'others_image' is already taken. "
@@ -352,7 +369,10 @@ def extract_cell(cell_label, ndim, nuc_label=None, rna_coord=None,
             else:
                 actual_keys.append(key)
             image_ = others_image[key]
-            stack.check_array(image_, ndim=2, dtype=[np.uint8, np.uint16])
+            stack.check_array(
+                image_,
+                ndim=2,
+                dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
             if image_.shape != image.shape:
                 warnings.warn("Image in 'others_image' does not have the same "
                               "shape ({0}) than original image ({1})."
@@ -518,16 +538,21 @@ def _check_nucleus_in_cell(cell_mask, nuc_mask):
         return True
 
 
-# TODO fix docstring
-def extract_spots_from_frame(spots, z_lim=None, y_lim=None, x_lim=None):
+def extract_spots_from_frame(
+        spots,
+        ndim,
+        z_lim=None,
+        y_lim=None,
+        x_lim=None):
     """Get spots coordinates within a given frame.
 
     Parameters
     ----------
     spots : np.ndarray
-        Coordinate of the spots detected inside foci, with shape (nb_spots, 3)
-        or (nb_spots, 4). One coordinate per dimension (zyx coordinates) plus
-        the index of the foci if necessary.
+        Coordinate of the spots. One coordinate per dimension first (zyx
+        coordinates or yx coordinates) plus additional dimensions if necessary.
+    ndim : {2, 3}
+        Number of spatial dimension to consider.
     z_lim : tuple[int, int]
         Minimum and maximum coordinate of the frame along the z axis.
     y_lim : tuple[int, int]
@@ -538,17 +563,23 @@ def extract_spots_from_frame(spots, z_lim=None, y_lim=None, x_lim=None):
     Returns
     -------
     extracted_spots : np.ndarray
-        Coordinate of the spots detected inside foci, with shape (nb_spots, 3)
-        or (nb_spots, 4). One coordinate per dimension (zyx coordinates) plus
-        the index of the foci if necessary.
+        Coordinate of the spots. One coordinate per dimension first (zyx
+        coordinates or yx coordinates) plus additional dimensions if necessary.
 
     """
     # check parameters
-    stack.check_array(spots, ndim=2, dtype=[np.int64, np.float64])
+    stack.check_array(
+        spots,
+        ndim=2,
+        dtype=[np.float32, np.float64, np.int32, np.int64])
     stack.check_parameter(
         z_lim=(tuple, type(None)),
         y_lim=(tuple, type(None)),
         x_lim=(tuple, type(None)))
+    if ndim not in [2, 3]:
+        raise ValueError("'ndim' should be 2 or 3.")
+    if ndim == 2:
+        z_lim = None
 
     # extract spots
     extracted_spots = spots.copy()
@@ -557,19 +588,26 @@ def extract_spots_from_frame(spots, z_lim=None, y_lim=None, x_lim=None):
         extracted_spots = extracted_spots[z_lim[0] < extracted_spots[:, 0]]
         extracted_spots[:, 0] -= z_lim[0]
     if y_lim is not None:
-        extracted_spots = extracted_spots[extracted_spots[:, 1] < y_lim[1]]
-        extracted_spots = extracted_spots[y_lim[0] < extracted_spots[:, 1]]
-        extracted_spots[:, 1] -= y_lim[0]
+        extracted_spots = extracted_spots[
+            extracted_spots[:, ndim - 2] < y_lim[1]]
+        extracted_spots = extracted_spots[
+            y_lim[0] < extracted_spots[:, ndim - 2]]
+        extracted_spots[:, ndim - 2] -= y_lim[0]
     if x_lim is not None:
-        extracted_spots = extracted_spots[extracted_spots[:, 2] < x_lim[1]]
-        extracted_spots = extracted_spots[x_lim[0] < extracted_spots[:, 2]]
-        extracted_spots[:, 2] -= x_lim[0]
+        extracted_spots = extracted_spots[
+            extracted_spots[:, ndim - 1] < x_lim[1]]
+        extracted_spots = extracted_spots[
+            x_lim[0] < extracted_spots[:, ndim - 1]]
+        extracted_spots[:, ndim - 1] -= x_lim[0]
 
     return extracted_spots
 
 
-def summarize_extraction_results(fov_results, ndim, path_output=None,
-                                 delimiter=";"):
+def summarize_extraction_results(
+        fov_results,
+        ndim,
+        path_output=None,
+        delimiter=";"):
     """Summarize results extracted from an image and store them in a dataframe.
 
     Parameters
@@ -596,9 +634,11 @@ def summarize_extraction_results(fov_results, ndim, path_output=None,
     -------
     df : pd.DataFrame
         Dataframe with summarized results from the field of view, at the cell
-        level. At least `cell_id` (Unique id of the cell) is returned. Other
-        indicators are summarized if available:
+        level. At least `cell_id` (Unique id of the cell) and 'cell_area' (2-d
+        area of the cell, in pixel) are returned. Other indicators are
+        summarized if available:
 
+        * `nuc_area`: 2-d area of the nucleus, in pixel.
         * `nb_rna`: Number of detected rna in the cell.
         * `nb_rna_in_nuc`: Number of detected rna inside the nucleus.
         * `nb_rna_out_nuc`: Number of detected rna outside the nucleus.
@@ -630,12 +670,15 @@ def summarize_extraction_results(fov_results, ndim, path_output=None,
             continue
         others_coord = cell_results[key]
         if (not isinstance(others_coord, np.ndarray)
-                or others_coord.dtype not in [np.int64, np.float64]):
+                or others_coord.dtype not in [
+                    np.float32, np.float64, np.int32, np.int64]):
             continue
         _extra_coord[key] = []
 
     # summarize results at the cell level
     _cell_id = []
+    _cell_area = []
+    _nuc_area = []
     _nb_rna = []
     _nb_rna_in_nuc = []
     _nb_rna_out_nuc = []
@@ -643,20 +686,27 @@ def summarize_extraction_results(fov_results, ndim, path_output=None,
         # get cell id
         _cell_id.append(cell_results["cell_id"])
 
+        # get cell area
+        cell_mask = cell_results["cell_mask"]
+        cell_area = int(cell_mask.sum())
+        _cell_area.append(cell_area)
+
         # get rna coordinates and relative results
         if "rna_coord" in cell_results:
             rna_coord = cell_results["rna_coord"]
             _nb_rna.append(len(rna_coord))
 
-            # get rna in nucleus
+            # get rna in nucleus and nucleus area
             if "nuc_mask" in cell_results:
                 nuc_mask = cell_results["nuc_mask"]
                 rna_in_nuc, rna_out_nuc = identify_objects_in_region(
                     nuc_mask,
                     rna_coord,
                     ndim)
+                nuc_area = int(nuc_mask.sum())
                 _nb_rna_in_nuc.append(len(rna_in_nuc))
                 _nb_rna_out_nuc.append(len(rna_out_nuc))
+                _nuc_area.append(nuc_area)
 
         # get others coordinates
         for key in _extra_coord:
@@ -671,21 +721,17 @@ def summarize_extraction_results(fov_results, ndim, path_output=None,
         _nb_rna_in_nuc = [np.nan] * n
     if len(_nb_rna_out_nuc) == 0:
         _nb_rna_out_nuc = [np.nan] * n
+    if len(_nuc_area) == 0:
+        _nuc_area = [np.nan] * n
 
     # store minimum results in a dataframe
     result_summary = {"cell_id": _cell_id,
+                      "cell_area": _cell_area,
+                      "nuc_area": _nuc_area,
                       "nb_rna": _nb_rna,
                       "nb_rna_in_nuc": _nb_rna_in_nuc,
                       "nb_rna_out_nuc": _nb_rna_out_nuc}
 
-    # store available results on nucleus and rna
-    if len(_nb_rna) > 0:
-        result_summary["nb_rna"] = _nb_rna
-    if len(_nb_rna_in_nuc) > 0:
-        result_summary["nb_rna_in_nuc"] = _nb_rna_in_nuc
-    if len(_nb_rna_out_nuc) > 0:
-        result_summary["nb_rna_out_nuc"] = _nb_rna_out_nuc
-
     # store results from others elements detected in the cell
     for key in _extra_coord:
         result_summary["nb_{0}".format(key)] = _extra_coord[key]
@@ -734,7 +780,7 @@ def center_mask_coord(main, others=None):
     stack.check_array(
         main,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64, bool])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
     stack.check_parameter(others=(list, type(None)))
     if others is not None and len(others) != 0:
         for x in others:
@@ -743,7 +789,7 @@ def center_mask_coord(main, others=None):
             stack.check_array(
                 x,
                 ndim=2,
-                dtype=[np.uint8, np.uint16, np.int64, bool])
+                dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
 
     # initialize parameter
     marge = stack.get_margin_value()
@@ -825,7 +871,7 @@ def from_boundaries_to_surface(binary_boundaries):
     stack.check_array(
         binary_boundaries,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64, bool])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
 
     # from binary boundaries to binary surface
     binary_surface = ndi.binary_fill_holes(binary_boundaries)
@@ -851,7 +897,7 @@ def from_surface_to_boundaries(binary_surface):
     stack.check_array(
         binary_surface,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64, bool])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
     original_dtype = binary_surface.dtype
 
     # pad the binary surface in case object if on the edge
@@ -883,7 +929,7 @@ def from_binary_to_coord(binary):
 
     Returns
     -------
-    coord : np.ndarray, np.int64
+    coord : np.ndarray, np.int
         Array of boundaries coordinates with shape (nb_points, 2).
 
     """
@@ -891,14 +937,20 @@ def from_binary_to_coord(binary):
     stack.check_array(
         binary,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64, bool])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
+
+    # store dtype
+    if binary.dtype == np.int32:
+        dtype = np.int32
+    else:
+        dtype = np.int64
 
     # we enlarge the binary mask with one pixel to be sure the external
     # boundaries of the object still fit within the frame
     binary_ = np.pad(binary, [(1, 1)], mode="constant")
 
     # get external boundaries coordinates
-    coord = find_contours(binary_, level=0)[0].astype(np.int64)
+    coord = find_contours(binary_, level=0)[0].astype(dtype)
 
     # remove the pad
     coord -= 1
@@ -912,17 +964,17 @@ def complete_coord_boundaries(coord):
 
     Parameters
     ----------
-    coord : np.ndarray, np.int64
+    coord : np.ndarray, np.int
         Array of coordinates to complete, with shape (nb_points, 2).
 
     Returns
     -------
-    coord_completed : np.ndarray, np.int64
+    coord_completed : np.ndarray, np.int
         Completed coordinates arrays, with shape (nb_points, 2).
 
     """
     # check parameters
-    stack.check_array(coord, ndim=2, dtype=[np.int64])
+    stack.check_array(coord, ndim=2, dtype=[np.int32, np.int64])
 
     # for each array in the list, complete its coordinates using the scikit
     # image method 'polygon_perimeter'
@@ -930,6 +982,7 @@ def complete_coord_boundaries(coord):
     coord_y = coord_y[:, np.newaxis]
     coord_x = coord_x[:, np.newaxis]
     coord_completed = np.concatenate((coord_y, coord_x), axis=-1)
+    coord_completed = coord_completed.astype(coord.dtype)
 
     return coord_completed
 
@@ -943,7 +996,7 @@ def from_coord_to_frame(coord, external_coord=True):
 
     Parameters
     ----------
-    coord : np.ndarray, np.int64
+    coord : np.ndarray, np.int
         Array of cell boundaries coordinates with shape (nb_points, 2) or
         (nb_points, 3).
     external_coord : bool
@@ -981,8 +1034,11 @@ def from_coord_to_frame(coord, external_coord=True):
     return frame_shape, min_y, min_x, marge
 
 
-def from_coord_to_surface(cell_coord, nuc_coord=None, rna_coord=None,
-                          external_coord=True):
+def from_coord_to_surface(
+        cell_coord,
+        nuc_coord=None,
+        rna_coord=None,
+        external_coord=True):
     """Convert 2-d coordinates to a binary matrix with the surface of the
     object.
 
@@ -995,11 +1051,11 @@ def from_coord_to_surface(cell_coord, nuc_coord=None, rna_coord=None,
 
     Parameters
     ----------
-    cell_coord : np.ndarray, np.int64
+    cell_coord : np.ndarray, np.int
         Array of cell boundaries coordinates with shape (nb_points, 2).
-    nuc_coord : np.ndarray, np.int64
+    nuc_coord : np.ndarray, np.int
         Array of nucleus boundaries coordinates with shape (nb_points, 2).
-    rna_coord : np.ndarray, np.int64
+    rna_coord : np.ndarray, np.int
         Array of mRNAs coordinates with shape (nb_points, 2) or
         (nb_points, 3).
     external_coord : bool
@@ -1013,16 +1069,16 @@ def from_coord_to_surface(cell_coord, nuc_coord=None, rna_coord=None,
         Binary image of nucleus surface with shape (y, x).
     rna_binary : np.ndarray, bool
         Binary image of mRNAs localizations with shape (y, x).
-    new_rna_coord : np.ndarray, np.int64
+    new_rna_coord : np.ndarray, np.int
         Array of mRNAs coordinates with shape (nb_points, 2) or (nb_points, 3).
 
     """
     # check parameters
-    stack.check_array(cell_coord, ndim=2, dtype=[np.int64])
+    stack.check_array(cell_coord, ndim=2, dtype=[np.int32, np.int64])
     if nuc_coord is not None:
-        stack.check_array(nuc_coord, ndim=2, dtype=[np.int64])
+        stack.check_array(nuc_coord, ndim=2, dtype=[np.int32, np.int64])
     if rna_coord is not None:
-        stack.check_array(rna_coord, ndim=2, dtype=[np.int64])
+        stack.check_array(rna_coord, ndim=2, dtype=[np.int32, np.int64])
     stack.check_parameter(external_coord=bool)
 
     # center coordinates
@@ -1065,7 +1121,7 @@ def from_coord_to_surface(cell_coord, nuc_coord=None, rna_coord=None,
             rna_binary[rna_coord_[:, 0], rna_coord_[:, 1]] = True
         else:
             rna_binary[rna_coord_[:, 1], rna_coord_[:, 2]] = True
-        new_rna_coord = rna_coord_.copy()
+        new_rna_coord = rna_coord_.copy().astype(rna_coord.dtype)
 
     else:
         rna_binary = None
diff --git a/bigfish/multistack/preprocess.py b/bigfish/multistack/preprocess.py
index 5e18f97..2597e58 100644
--- a/bigfish/multistack/preprocess.py
+++ b/bigfish/multistack/preprocess.py
@@ -23,8 +23,11 @@
 
 # ### Building stack ###
 
-def build_stacks(data_map, input_dimension=None, sanity_check=False,
-                 return_origin=False):
+def build_stacks(
+        data_map,
+        input_dimension=None,
+        sanity_check=False,
+        return_origin=False):
     """Generator to build several stacks from recipe-folder pairs.
 
     To build a stack, a recipe should be linked to a directory including all
@@ -145,8 +148,12 @@ def build_stacks(data_map, input_dimension=None, sanity_check=False,
                 yield tensor
 
 
-def build_stack(recipe, input_folder, input_dimension=None, sanity_check=False,
-                i_fov=0):
+def build_stack(
+        recipe,
+        input_folder,
+        input_dimension=None,
+        sanity_check=False,
+        i_fov=0):
     """Build a 5-d stack from the same field of view (fov).
 
     The recipe dictionary for one field of view takes the form:
@@ -577,8 +584,8 @@ def build_stack_no_recipe(paths, input_dimension=None, sanity_check=False):
     if sanity_check:
         stack.check_array(
             tensor,
-            dtype=[np.uint8, np.uint16, np.uint32,
-                   np.int8, np.int16, np.int32,
+            dtype=[np.uint8, np.uint16, np.uint32, np.uint64,
+                   np.int8, np.int16, np.int32, np.int64,
                    np.float16, np.float32, np.float64,
                    bool],
             ndim=5,
diff --git a/bigfish/plot/__init__.py b/bigfish/plot/__init__.py
index 65b5f15..29c1039 100644
--- a/bigfish/plot/__init__.py
+++ b/bigfish/plot/__init__.py
@@ -11,10 +11,10 @@
 from .plot_images import plot_segmentation
 from .plot_images import plot_segmentation_boundary
 from .plot_images import plot_segmentation_diff
-
 from .plot_images import plot_detection
 from .plot_images import plot_reference_spot
 from .plot_images import plot_cell
+from .plot_images import plot_cell_coordinates
 
 from .plot_quality import plot_sharpness
 from .plot_quality import plot_elbow
@@ -33,7 +33,8 @@
     "plot_segmentation_diff",
     "plot_detection",
     "plot_reference_spot",
-    "plot_cell"]
+    "plot_cell",
+    "plot_cell_coordinates"]
 
 _quality = [
     "plot_sharpness",
diff --git a/bigfish/plot/plot_images.py b/bigfish/plot/plot_images.py
index 1088035..aaf6672 100644
--- a/bigfish/plot/plot_images.py
+++ b/bigfish/plot/plot_images.py
@@ -23,9 +23,19 @@
 
 # ### General plot ###
 
-def plot_yx(image, r=0, c=0, z=0, rescale=False, contrast=False,
-            title=None, framesize=(10, 10), remove_frame=True,
-            path_output=None, ext="png", show=True):
+def plot_yx(
+        image,
+        r=0,
+        c=0,
+        z=0,
+        rescale=False,
+        contrast=False,
+        title=None,
+        framesize=(10, 10),
+        remove_frame=True,
+        path_output=None,
+        ext="png",
+        show=True):
     """Plot the selected yx plan of the selected dimensions of an image.
 
     Parameters
@@ -62,7 +72,9 @@ def plot_yx(image, r=0, c=0, z=0, rescale=False, contrast=False,
     stack.check_array(
         image,
         ndim=[2, 3, 4, 5],
-        dtype=[np.uint8, np.uint16, np.int64, np.float32, np.float64, bool])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64,
+               np.float32, np.float64,
+               bool])
     stack.check_parameter(
         r=int, c=int, z=int,
         rescale=bool,
@@ -112,9 +124,16 @@ def plot_yx(image, r=0, c=0, z=0, rescale=False, contrast=False,
         plt.close()
 
 
-def plot_images(images, rescale=False, contrast=False, titles=None,
-                framesize=(15, 10), remove_frame=True, path_output=None,
-                ext="png", show=True):
+def plot_images(
+        images,
+        rescale=False,
+        contrast=False,
+        titles=None,
+        framesize=(15, 10),
+        remove_frame=True,
+        path_output=None,
+        ext="png",
+        show=True):
     """Plot or subplot of 2-d images.
 
     Parameters
@@ -139,7 +158,6 @@ def plot_images(images, rescale=False, contrast=False, titles=None,
     show : bool, default=True
         Show the figure or not.
 
-
     """
     # enlist image if necessary
     if isinstance(images, np.ndarray):
@@ -160,10 +178,14 @@ def plot_images(images, rescale=False, contrast=False, titles=None,
         stack.check_array(
             image,
             ndim=2,
-            dtype=[np.uint8, np.uint16, np.int64,
+            dtype=[np.uint8, np.uint16, np.int32, np.int64,
                    np.float32, np.float64,
                    bool])
 
+    # enlist 'titles' if needed
+    if titles is not None and isinstance(titles, str):
+        titles = [titles]
+
     # we plot 3 images by row maximum
     nrow = int(np.ceil(len(images)/3))
     ncol = min(len(images), 3)
@@ -247,9 +269,17 @@ def plot_images(images, rescale=False, contrast=False, titles=None,
 
 # ### Segmentation plot ###
 
-def plot_segmentation(image, mask, rescale=False, contrast=False, title=None,
-                      framesize=(15, 10), remove_frame=True,
-                      path_output=None, ext="png", show=True):
+def plot_segmentation(
+        image,
+        mask,
+        rescale=False,
+        contrast=False,
+        title=None,
+        framesize=(15, 10),
+        remove_frame=True,
+        path_output=None,
+        ext="png",
+        show=True):
     """Plot result of a 2-d segmentation, with labelled instances if available.
 
     Parameters
@@ -281,11 +311,13 @@ def plot_segmentation(image, mask, rescale=False, contrast=False, title=None,
     stack.check_array(
         image,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64, np.float32, np.float64, bool])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64,
+               np.float32, np.float64,
+               bool])
     stack.check_array(
         mask,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64, bool])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
     stack.check_parameter(
         rescale=bool,
         contrast=bool,
@@ -346,11 +378,19 @@ def plot_segmentation(image, mask, rescale=False, contrast=False, title=None,
         plt.close()
 
 
-def plot_segmentation_boundary(image, cell_label=None, nuc_label=None,
-                               boundary_size=1, rescale=False, contrast=False,
-                               title=None, framesize=(10, 10),
-                               remove_frame=True, path_output=None, ext="png",
-                               show=True):
+def plot_segmentation_boundary(
+        image,
+        cell_label=None,
+        nuc_label=None,
+        boundary_size=1,
+        rescale=False,
+        contrast=False,
+        title=None,
+        framesize=(10, 10),
+        remove_frame=True,
+        path_output=None,
+        ext="png",
+        show=True):
     """Plot the boundary of the segmented objects.
 
     Parameters
@@ -386,17 +426,19 @@ def plot_segmentation_boundary(image, cell_label=None, nuc_label=None,
     stack.check_array(
         image,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64, np.float32, np.float64, bool])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64,
+               np.float32, np.float64,
+               bool])
     if cell_label is not None:
         stack.check_array(
             cell_label,
             ndim=2,
-            dtype=[np.uint8, np.uint16, np.int64, bool])
+            dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
     if nuc_label is not None:
         stack.check_array(
             nuc_label,
             ndim=2,
-            dtype=[np.uint8, np.uint16, np.int64, bool])
+            dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
     stack.check_parameter(
         rescale=bool,
         contrast=bool,
@@ -461,10 +503,18 @@ def plot_segmentation_boundary(image, cell_label=None, nuc_label=None,
         plt.close()
 
 
-def plot_segmentation_diff(image, mask_pred, mask_gt, rescale=False,
-                           contrast=False, title=None, framesize=(15, 10),
-                           remove_frame=True, path_output=None, ext="png",
-                           show=True):
+def plot_segmentation_diff(
+        image,
+        mask_pred,
+        mask_gt,
+        rescale=False,
+        contrast=False,
+        title=None,
+        framesize=(15, 10),
+        remove_frame=True,
+        path_output=None,
+        ext="png",
+        show=True):
     """Plot segmentation results along with ground truth to compare.
 
     Parameters
@@ -507,7 +557,9 @@ def plot_segmentation_diff(image, mask_pred, mask_gt, rescale=False,
     stack.check_array(
         image,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64, np.float32, np.float64, bool])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64,
+               np.float32, np.float64,
+               bool])
     stack.check_array(
         mask_pred,
         ndim=2,
@@ -569,10 +621,22 @@ def plot_segmentation_diff(image, mask_pred, mask_gt, rescale=False,
 
 # ### Detection plot ###
 
-def plot_detection(image, spots, shape="circle", radius=3, color="red",
-                   linewidth=1, fill=False, rescale=False, contrast=False,
-                   title=None, framesize=(15, 10), remove_frame=True,
-                   path_output=None, ext="png", show=True):
+def plot_detection(
+        image,
+        spots,
+        shape="circle",
+        radius=3,
+        color="red",
+        linewidth=1,
+        fill=False,
+        rescale=False,
+        contrast=False,
+        title=None,
+        framesize=(15, 10),
+        remove_frame=True,
+        path_output=None,
+        ext="png",
+        show=True):
     """Plot detected spots and foci on a 2-d image.
 
     Parameters
@@ -626,7 +690,8 @@ def plot_detection(image, spots, shape="circle", radius=3, color="red",
     stack.check_array(
         image,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64, np.float32, np.float64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64,
+               np.float32, np.float64])
     stack.check_parameter(
         spots=(list, np.ndarray),
         shape=(list, str),
@@ -644,9 +709,15 @@ def plot_detection(image, spots, shape="circle", radius=3, color="red",
         show=bool)
     if isinstance(spots, list):
         for spots_ in spots:
-            stack.check_array(spots_, ndim=2, dtype=[np.int64, np.float64])
+            stack.check_array(
+                spots_,
+                ndim=2,
+                dtype=[np.float32, np.float64, np.int32, np.int64])
     else:
-        stack.check_array(spots, ndim=2, dtype=[np.int64, np.float64])
+        stack.check_array(
+            spots,
+            ndim=2,
+            dtype=[np.float32, np.float64, np.int32, np.int64])
 
     # enlist and format parameters
     if not isinstance(spots, list):
@@ -713,8 +784,8 @@ def plot_detection(image, spots, shape="circle", radius=3, color="red",
 
         # plot symbols
         for y, x in coordinates_2d:
-            x = _define_patch(x, y, shape[i], radius[i], color[i],
-                              linewidth[i], fill[i])
+            x = _define_patch(
+                x, y, shape[i], radius[i], color[i], linewidth[i], fill[i])
             ax[1].add_patch(x)
 
     # titles and frames
@@ -794,9 +865,16 @@ def _define_patch(x, y, shape, radius, color, linewidth, fill):
     return x
 
 
-def plot_reference_spot(reference_spot, rescale=False, contrast=False,
-                        title=None, framesize=(5, 5), remove_frame=True,
-                        path_output=None, ext="png", show=True):
+def plot_reference_spot(
+        reference_spot,
+        rescale=False,
+        contrast=False,
+        title=None,
+        framesize=(5, 5),
+        remove_frame=True,
+        path_output=None,
+        ext="png",
+        show=True):
     """Plot the selected yx plan of the selected dimensions of an image.
 
     Parameters
@@ -826,7 +904,8 @@ def plot_reference_spot(reference_spot, rescale=False, contrast=False,
     stack.check_array(
         reference_spot,
         ndim=[2,  3],
-        dtype=[np.uint8, np.uint16, np.int64, np.float32, np.float64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64,
+               np.float32, np.float64])
     stack.check_parameter(
         rescale=bool,
         contrast=bool,
@@ -873,11 +952,25 @@ def plot_reference_spot(reference_spot, rescale=False, contrast=False,
 
 # ### Individual cell plot ###
 
-def plot_cell(ndim, cell_coord=None, nuc_coord=None, rna_coord=None,
-              foci_coord=None, other_coord=None, image=None, cell_mask=None,
-              nuc_mask=None, boundary_size=1, title=None, remove_frame=True,
-              rescale=False, contrast=False, framesize=(15, 10),
-              path_output=None, ext="png", show=True):
+def plot_cell(
+        ndim,
+        cell_coord=None,
+        nuc_coord=None,
+        rna_coord=None,
+        foci_coord=None,
+        other_coord=None,
+        image=None,
+        cell_mask=None,
+        nuc_mask=None,
+        boundary_size=1,
+        title=None,
+        remove_frame=True,
+        rescale=False,
+        contrast=False,
+        framesize=(15, 10),
+        path_output=None,
+        ext="png",
+        show=True):
     """
     Plot image and coordinates extracted for a specific cell.
 
@@ -885,25 +978,25 @@ def plot_cell(ndim, cell_coord=None, nuc_coord=None, rna_coord=None,
     ----------
     ndim : {2, 3}
         Number of spatial dimensions to consider in the coordinates.
-    cell_coord : np.ndarray, np.int64, optional
+    cell_coord : np.ndarray, optional
         Coordinates of the cell border with shape (nb_points, 2). If None,
         coordinate representation of the cell is not shown.
-    nuc_coord : np.ndarray, np.int64, optional
+    nuc_coord : np.ndarray, optional
         Coordinates of the nucleus border with shape (nb_points, 2).
-    rna_coord : np.ndarray, np.int64, optional
+    rna_coord : np.ndarray, optional
         Coordinates of the detected spots with shape (nb_spots, 4) or
         (nb_spots, 3). One coordinate per dimension (zyx or yx dimensions)
         plus the index of the cluster assigned to the spot. If no cluster was
         assigned, value is -1. If only coordinates of spatial dimensions are
         available, only centroid of foci can be shown.
-    foci_coord : np.ndarray, np.int64, optional
+    foci_coord : np.ndarray, optional
         Array with shape (nb_foci, 5) or (nb_foci, 4). One coordinate per
         dimension for the foci centroid (zyx or yx dimensions), the number of
         spots detected in the foci and its index.
-    other_coord : np.ndarray, np.int64, optional
+    other_coord : np.ndarray, optional
         Coordinates of the detected elements with shape (nb_elements, 3) or
         (nb_elements, 2). One coordinate per dimension (zyx or yx dimensions).
-    image : np.ndarray, np.uint, optional
+    image : np.ndarray, optional
         Original image of the cell with shape (y, x). If None, original image
         of the cell is not shown.
     cell_mask : np.ndarray, optional
@@ -936,30 +1029,46 @@ def plot_cell(ndim, cell_coord=None, nuc_coord=None, rna_coord=None,
 
     # check parameters
     if cell_coord is not None:
-        stack.check_array(cell_coord, ndim=2, dtype=np.int64)
+        stack.check_array(
+            cell_coord,
+            ndim=2,
+            dtype=[np.float32, np.float64, np.int32, np.int64])
     if nuc_coord is not None:
-        stack.check_array(nuc_coord, ndim=2, dtype=np.int64)
+        stack.check_array(
+            nuc_coord,
+            ndim=2,
+            dtype=[np.float32, np.float64, np.int32, np.int64])
     if rna_coord is not None:
-        stack.check_array(rna_coord, ndim=2, dtype=np.int64)
+        stack.check_array(
+            rna_coord,
+            ndim=2,
+            dtype=[np.float32, np.float64, np.int32, np.int64])
     if foci_coord is not None:
-        stack.check_array(foci_coord, ndim=2, dtype=np.int64)
+        stack.check_array(
+            foci_coord,
+            ndim=2,
+            dtype=[np.float32, np.float64, np.int32, np.int64])
     if other_coord is not None:
-        stack.check_array(other_coord, ndim=2, dtype=np.int64)
+        stack.check_array(
+            other_coord,
+            ndim=2,
+            dtype=[np.float32, np.float64, np.int32, np.int64])
     if image is not None:
         stack.check_array(
             image,
             ndim=2,
-            dtype=[np.uint8, np.uint16, np.int64, np.float32, np.float64])
+            dtype=[np.uint8, np.uint16, np.int32, np.int64,
+                   np.float32, np.float64])
     if cell_mask is not None:
         stack.check_array(
             cell_mask,
             ndim=2,
-            dtype=[np.uint8, np.uint16, np.int64, bool])
+            dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
     if nuc_mask is not None:
         stack.check_array(
             nuc_mask,
             ndim=2,
-            dtype=[np.uint8, np.uint16, np.int64, bool])
+            dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
     stack.check_parameter(
         ndim=int,
         boundary_size=int,
@@ -1180,3 +1289,240 @@ def plot_cell(ndim, cell_coord=None, nuc_coord=None, rna_coord=None,
             path_output=path_output,
             ext=ext,
             show=show)
+
+
+def plot_cell_coordinates(
+        ndim,
+        cell_coord,
+        nuc_coord,
+        rna_coord,
+        titles=None,
+        remove_frame=True,
+        framesize=(10, 5),
+        path_output=None,
+        ext="png",
+        show=True):
+    """
+    Plot cell coordinates for one or several cells.
+
+    Parameters
+    ----------
+    ndim : {2, 3}
+        Number of spatial dimensions to consider in the coordinates.
+    cell_coord : np.ndarray or list
+        Coordinates or list of coordinates of the cell border with shape
+        (nb_points, 2).
+    nuc_coord : np.ndarray or list
+        Coordinates or list of coordinates of the nucleus border with shape
+        (nb_points, 2).
+    rna_coord : np.ndarray or list
+        Coordinates or list of coordinates of the detected spots with shape
+        (nb_spots, 3) or (nb_spots, 2). One coordinate per dimension (zyx or
+        yx dimensions).
+    titles : str or list, optional
+        Title or list of titles.
+    remove_frame : bool, default=True
+        Remove axes and frame.
+    framesize : tuple, default=(10, 5)
+        Size of the frame.
+    path_output : str, optional
+        Path to save the image (without extension).
+    ext : str or list, default='png'
+        Extension used to save the plot. If it is a list of strings, the plot
+        will be saved several times.
+    show : bool, default=True
+        Show the figure or not.
+
+    """
+    # enlist coordinates if necessary
+    if isinstance(cell_coord, np.ndarray):
+        cell_coord = [cell_coord]
+    if isinstance(nuc_coord, np.ndarray):
+        nuc_coord = [nuc_coord]
+    if isinstance(rna_coord, np.ndarray):
+        rna_coord = [rna_coord]
+
+    # check parameters
+    stack.check_parameter(
+        ndim=int,
+        titles=(str, list, type(None)),
+        remove_frame=bool,
+        framesize=tuple,
+        path_output=(str, type(None)),
+        ext=(str, list))
+
+    # check coordinates
+    for i in range(len(cell_coord)):
+        stack.check_array(
+            cell_coord[i],
+            ndim=2,
+            dtype=[np.float32, np.float64, np.int32, np.int64])
+        stack.check_array(
+            nuc_coord[i],
+            ndim=2,
+            dtype=[np.float32, np.float64, np.int32, np.int64])
+        stack.check_array(
+            rna_coord[i],
+            ndim=2,
+            dtype=[np.float32, np.float64, np.int32, np.int64])
+
+    # enlist 'titles' if needed
+    if titles is not None and isinstance(titles, str):
+        titles = [titles]
+
+    # we plot 3 images by row maximum
+    nrow = int(np.ceil(len(cell_coord) / 3))
+    ncol = min(len(cell_coord), 3)
+
+    # plot one image
+    if len(cell_coord) == 1:
+
+        # frame
+        if remove_frame:
+            fig = plt.figure(figsize=framesize, frameon=False)
+            ax = fig.add_axes([0, 0, 1, 1])
+            ax.axis('off')
+        else:
+            plt.figure(figsize=framesize)
+
+        # coordinate image
+        plt.plot(
+            cell_coord[0][:, 1],
+            cell_coord[0][:, 0],
+            c="black",
+            linewidth=2)
+        plt.plot(
+            nuc_coord[0][:, 1],
+            nuc_coord[0][:, 0],
+            c="steelblue",
+            linewidth=2)
+        plt.scatter(
+            rna_coord[0][:, ndim - 1],
+            rna_coord[0][:, ndim - 2],
+            s=25,
+            c="firebrick",
+            marker=".")
+
+        # titles and frames
+        _, _, min_y, max_y = plt.axis()
+        plt.ylim(max_y, min_y)
+        plt.use_sticky_edges = True
+        plt.margins(0.01, 0.01)
+        plt.axis('scaled')
+        if titles is not None:
+            plt.title(
+                titles[0],
+                fontweight="bold",
+                fontsize=10)
+        if not remove_frame:
+            plt.tight_layout()
+
+        # output
+        if path_output is not None:
+            save_plot(path_output, ext)
+        if show:
+            plt.show()
+        else:
+            plt.close()
+
+        return
+
+    # plot multiple images
+    fig, ax = plt.subplots(nrow, ncol, figsize=framesize)
+
+    # one row
+    if len(cell_coord) in [2, 3]:
+
+        # loop over instance coordinates
+        for i in range(len(cell_coord)):
+
+            # coordinate image
+            ax[i].plot(
+                cell_coord[i][:, 1],
+                cell_coord[i][:, 0],
+                c="black",
+                linewidth=2)
+            ax[i].plot(
+                nuc_coord[i][:, 1],
+                nuc_coord[i][:, 0],
+                c="steelblue",
+                linewidth=2)
+            ax[i].scatter(
+                rna_coord[i][:, ndim - 1],
+                rna_coord[i][:, ndim - 2],
+                s=25,
+                c="firebrick",
+                marker=".")
+
+            # titles and frames
+            _, _, min_y, max_y = ax[i].axis()
+            ax[i].set_ylim(max_y, min_y)
+            ax[i].use_sticky_edges = True
+            ax[i].margins(0.01, 0.01)
+            ax[i].axis('scaled')
+            if remove_frame:
+                ax[i].axis("off")
+            if titles is not None:
+                ax[i].set_title(
+                    titles[i],
+                    fontweight="bold",
+                    fontsize=10)
+
+    # several rows
+    else:
+
+        # we complete the row with empty frames
+        r = nrow * 3 - len(cell_coord)
+        cell_coord_completed = [cell_coord_ for cell_coord_ in cell_coord]
+        cell_coord_completed += [None] * r
+
+        # loop over instance coordinates
+        for i in range(len(cell_coord_completed)):
+            row = i // 3
+            col = i % 3
+
+            # empty subplot
+            if cell_coord_completed[i] is None:
+                ax[row, col].set_visible(False)
+                continue
+
+            # coordinate image
+            ax[row, col].plot(
+                cell_coord_completed[i][:, 1],
+                cell_coord_completed[i][:, 0],
+                c="black",
+                linewidth=2)
+            ax[row, col].plot(
+                nuc_coord[i][:, 1],
+                nuc_coord[i][:, 0],
+                c="steelblue",
+                linewidth=2)
+            ax[row, col].scatter(
+                rna_coord[i][:, ndim - 1],
+                rna_coord[i][:, ndim - 2],
+                s=25,
+                c="firebrick",
+                marker=".")
+
+            # titles and frames
+            _, _, min_y, max_y = ax[row, col].axis()
+            ax[row, col].set_ylim(max_y, min_y)
+            ax[row, col].use_sticky_edges = True
+            ax[row, col].margins(0.01, 0.01)
+            ax[row, col].axis('scaled')
+            if remove_frame:
+                ax[row, col].axis("off")
+            if titles is not None:
+                ax[row, col].set_title(
+                    titles[i],
+                    fontweight="bold",
+                    fontsize=10)
+
+    # output
+    plt.tight_layout()
+    if path_output is not None:
+        save_plot(path_output, ext)
+    if show:
+        plt.show()
+    else:
+        plt.close()
diff --git a/bigfish/plot/plot_quality.py b/bigfish/plot/plot_quality.py
index bfeb31e..8b45061 100644
--- a/bigfish/plot/plot_quality.py
+++ b/bigfish/plot/plot_quality.py
@@ -18,9 +18,17 @@
 
 # ### Focus - sharpness ###
 
-def plot_sharpness(focus_measures, labels=None, title=None, framesize=(5, 5),
-                   size_title=20, size_axes=15, size_legend=15,
-                   path_output=None, ext="png", show=True):
+def plot_sharpness(
+        focus_measures,
+        labels=None,
+        title=None,
+        framesize=(5, 5),
+        size_title=20,
+        size_axes=15,
+        size_legend=15,
+        path_output=None,
+        ext="png",
+        show=True):
     """Plot focus measures of a 3-d image, at the z-slice level.
 
     A measure of focus for each z-slice can be computed by averaging the
@@ -105,10 +113,20 @@ def plot_sharpness(focus_measures, labels=None, title=None, framesize=(5, 5),
 
 # ### Elbow plots ###
 
-def plot_elbow(images, voxel_size=None, spot_radius=None, log_kernel_size=None,
-               minimum_distance=None, title=None, framesize=(5, 5),
-               size_title=20, size_axes=15, size_legend=15, path_output=None,
-               ext="png", show=True):
+def plot_elbow(
+        images,
+        voxel_size=None,
+        spot_radius=None,
+        log_kernel_size=None,
+        minimum_distance=None,
+        title=None,
+        framesize=(5, 5),
+        size_title=20,
+        size_axes=15,
+        size_legend=15,
+        path_output=None,
+        ext="png",
+        show=True):
     """Plot the elbow curve that allows an automated spot detection.
 
     Parameters
@@ -208,10 +226,19 @@ def plot_elbow(images, voxel_size=None, spot_radius=None, log_kernel_size=None,
         plt.close()
 
 
-def plot_elbow_colocalized(spots_1, spots_2, voxel_size, threshold_max=None,
-                           title=None, framesize=(5, 5), size_title=20,
-                           size_axes=15, size_legend=15, path_output=None,
-                           ext="png", show=True):
+def plot_elbow_colocalized(
+        spots_1,
+        spots_2,
+        voxel_size,
+        threshold_max=None,
+        title=None,
+        framesize=(5, 5),
+        size_title=20,
+        size_axes=15,
+        size_legend=15,
+        path_output=None,
+        ext="png",
+        show=True):
     """Plot the elbow curve that allows an automated colocalized spot
     detection.
 
diff --git a/bigfish/segmentation/cell_segmentation.py b/bigfish/segmentation/cell_segmentation.py
index a28a441..35ab48d 100644
--- a/bigfish/segmentation/cell_segmentation.py
+++ b/bigfish/segmentation/cell_segmentation.py
@@ -44,8 +44,13 @@ def unet_distance_edge_double():
     return model
 
 
-def apply_unet_distance_double(model, nuc, cell, nuc_label, target_size=None,
-                               test_time_augmentation=False):
+def apply_unet_distance_double(
+        model,
+        nuc,
+        cell,
+        nuc_label,
+        target_size=None,
+        test_time_augmentation=False):
     """Segment cell with a pretrained model to predict distance map and  use
     it with a watershed algorithm.
 
@@ -203,8 +208,12 @@ def apply_unet_distance_double(model, nuc, cell, nuc_label, target_size=None,
     return cell_label_pred
 
 
-def from_distance_to_instances(label_x_nuc, label_2_cell, label_distance,
-                               nuc_3_classes=False, compute_nuc_label=False):
+def from_distance_to_instances(
+        label_x_nuc,
+        label_2_cell,
+        label_distance,
+        nuc_3_classes=False,
+        compute_nuc_label=False):
     """Extract instance labels from a distance map and a binary surface
     prediction with a watershed algorithm.
 
@@ -237,8 +246,8 @@ def from_distance_to_instances(label_x_nuc, label_2_cell, label_distance,
         nuc_3_classes=bool,
         compute_nuc_label=bool)
     stack.check_array(label_x_nuc, ndim=2, dtype=[np.float32, np.int64])
-    stack.check_array(label_2_cell, ndim=2, dtype=[np.float32])
-    stack.check_array(label_distance, ndim=2, dtype=[np.uint16])
+    stack.check_array(label_2_cell, ndim=2, dtype=np.float32)
+    stack.check_array(label_distance, ndim=2, dtype=np.uint16)
 
     # get nuclei labels
     if nuc_3_classes and compute_nuc_label:
@@ -451,7 +460,7 @@ def apply_watershed(watershed_relief, nuc_label, cell_mask):
     stack.check_array(
         watershed_relief,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64])
     stack.check_array(nuc_label, ndim=2, dtype=np.int64)
     stack.check_array(cell_mask, ndim=2, dtype=bool)
 
diff --git a/bigfish/segmentation/nuc_segmentation.py b/bigfish/segmentation/nuc_segmentation.py
index 9d459d9..0c87e98 100644
--- a/bigfish/segmentation/nuc_segmentation.py
+++ b/bigfish/segmentation/nuc_segmentation.py
@@ -38,8 +38,11 @@ def unet_3_classes_nuc():
     return model
 
 
-def apply_unet_3_classes(model, image, target_size=None,
-                         test_time_augmentation=False):
+def apply_unet_3_classes(
+        model,
+        image,
+        target_size=None,
+        test_time_augmentation=False):
     """Segment image with a 3-classes trained model.
 
     Parameters
@@ -168,7 +171,7 @@ def from_3_classes_to_instances(label_3_classes):
 
     """
     # check parameters
-    stack.check_array(label_3_classes, ndim=3, dtype=[np.float32])
+    stack.check_array(label_3_classes, ndim=3, dtype=np.float32)
 
     # get classes indices
     label_3_classes = np.argmax(label_3_classes, axis=-1)
diff --git a/bigfish/segmentation/postprocess.py b/bigfish/segmentation/postprocess.py
index 6050257..c74a7ad 100644
--- a/bigfish/segmentation/postprocess.py
+++ b/bigfish/segmentation/postprocess.py
@@ -15,8 +15,6 @@
 from skimage.morphology import remove_small_objects
 
 
-# TODO make functions compatible with different type of integers
-
 # ### Labelled images ###
 
 def label_instances(image_binary):
@@ -38,7 +36,7 @@ def label_instances(image_binary):
     stack.check_array(image_binary, ndim=[2, 3], dtype=bool)
 
     # label instances
-    image_label = label(image_binary)
+    image_label = label(image_binary).astype(np.int64)
 
     return image_label
 
@@ -84,8 +82,12 @@ def merge_labels(image_label_1, image_label_2):
 
 # ### Clean segmentation ###
 # TODO make it available for 3D images
-def clean_segmentation(image, small_object_size=None, fill_holes=False,
-                       smoothness=None, delimit_instance=False):
+def clean_segmentation(
+        image,
+        small_object_size=None,
+        fill_holes=False,
+        smoothness=None,
+        delimit_instance=False):
     """Clean segmentation results (binary masks or integer labels).
 
     Parameters
@@ -279,7 +281,7 @@ def remove_disjoint(image):
     stack.check_array(
         image,
         ndim=[2, 3],
-        dtype=[np.uint8, np.uint16, np.int64, bool])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
 
     # handle boolean array
     cast_to_bool = False
diff --git a/bigfish/segmentation/utils.py b/bigfish/segmentation/utils.py
index 4e768a3..1a3b2ec 100644
--- a/bigfish/segmentation/utils.py
+++ b/bigfish/segmentation/utils.py
@@ -13,8 +13,6 @@
 from skimage.measure import regionprops
 
 
-# TODO make functions compatible with different type of integers
-
 # ### Thresholding method ###
 
 def thresholding(image, threshold):
@@ -23,7 +21,7 @@ def thresholding(image, threshold):
 
     Parameters
     ----------
-    image : np.ndarray, np.uint
+    image : np.ndarray
         A 2-d image to segment with shape (y, x).
     threshold : int or float
         Pixel intensity threshold used to discriminate foreground from
@@ -36,7 +34,11 @@ def thresholding(image, threshold):
 
     """
     # check parameters
-    stack.check_array(image, ndim=2, dtype=[np.uint8, np.uint16])
+    stack.check_array(
+        image,
+        ndim=2,
+        dtype=[np.uint8, np.uint16, np.int32, np.int64,
+               np.float32, np.float64])
     stack.check_parameter(threshold=(float, int))
 
     # discriminate nuclei from background, applying a threshold.
@@ -68,7 +70,7 @@ def compute_mean_diameter(image_label):
     stack.check_array(
         image_label,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64])
 
     # compute properties of the segmented instances
     props = regionprops(image_label)
@@ -107,7 +109,7 @@ def compute_mean_convexity_ratio(image_label):
     stack.check_array(
         image_label,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64])
 
     # compute properties of the segmented instances
     props = regionprops(image_label)
@@ -145,7 +147,7 @@ def compute_surface_ratio(image_label):
     stack.check_array(
         image_label,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64])
 
     # compute surface ratio
     surface_instances = image_label > 0
@@ -173,7 +175,7 @@ def count_instances(image_label):
     stack.check_array(
         image_label,
         ndim=2,
-        dtype=[np.uint8, np.uint16, np.int64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64])
 
     indices = set(image_label.ravel())
     if 0 in indices:
diff --git a/bigfish/stack/filter.py b/bigfish/stack/filter.py
index c3d2c09..3b0d133 100644
--- a/bigfish/stack/filter.py
+++ b/bigfish/stack/filter.py
@@ -14,10 +14,18 @@
 from .preprocess import cast_img_uint8
 from .preprocess import cast_img_uint16
 
-from skimage.morphology.selem import square
-from skimage.morphology.selem import diamond
-from skimage.morphology.selem import rectangle
-from skimage.morphology.selem import disk
+import skimage
+from sklearn.utils.fixes import parse_version
+if parse_version(skimage.__version__) < parse_version("0.19.0"):
+    from skimage.morphology.selem import square
+    from skimage.morphology.selem import diamond
+    from skimage.morphology.selem import rectangle
+    from skimage.morphology.selem import disk
+else:
+    from skimage.morphology.footprints import square
+    from skimage.morphology.footprints import diamond
+    from skimage.morphology.footprints import rectangle
+    from skimage.morphology.footprints import disk
 from skimage.morphology import binary_dilation
 from skimage.morphology import dilation
 from skimage.morphology import binary_erosion
diff --git a/bigfish/stack/io.py b/bigfish/stack/io.py
index d932516..a1f5065 100644
--- a/bigfish/stack/io.py
+++ b/bigfish/stack/io.py
@@ -120,8 +120,12 @@ def read_array(path):
     return array
 
 
-def read_array_from_csv(path, dtype=None, delimiter=";", encoding="utf-8",
-                        skiprows=0):
+def read_array_from_csv(
+        path,
+        dtype=None,
+        delimiter=";",
+        encoding="utf-8",
+        skiprows=0):
     """Read a numpy array saved in a ``csv`` file.
 
     Parameters
@@ -381,7 +385,7 @@ def save_array(array, path):
                np.int8, np.int16, np.int32, np.int64,
                np.float16, np.float32, np.float64,
                bool],
-        ndim=[2, 3, 4, 5])
+        ndim=[1, 2, 3, 4, 5])
 
     # add extension if necessary
     if ".npy" not in path:
diff --git a/bigfish/stack/preprocess.py b/bigfish/stack/preprocess.py
index 83a30a3..0577e4e 100644
--- a/bigfish/stack/preprocess.py
+++ b/bigfish/stack/preprocess.py
@@ -43,7 +43,10 @@ def compute_image_standardization(image):
 
     """
     # check parameters
-    check_array(image, ndim=2, dtype=[np.uint8, np.uint16, np.float32])
+    check_array(
+        image,
+        ndim=2,
+        dtype=[np.uint8, np.uint16, np.float32, np.float64])
 
     # check image is in 2D
     if len(image.shape) != 2:
@@ -454,7 +457,10 @@ def resize_image(image, output_shape, method="bilinear"):
     """
     # check parameters
     check_parameter(output_shape=tuple, method=str)
-    check_array(image, ndim=[2, 3], dtype=[np.uint8, np.uint16, np.float32])
+    check_array(
+        image,
+        ndim=[2, 3],
+        dtype=[np.uint8, np.uint16, np.float32, np.float64])
 
     # resize image
     if method == "bilinear":
diff --git a/bigfish/stack/projection.py b/bigfish/stack/projection.py
index e2aefbd..947dc1f 100644
--- a/bigfish/stack/projection.py
+++ b/bigfish/stack/projection.py
@@ -32,7 +32,8 @@ def maximum_projection(image):
     check_array(
         image,
         ndim=3,
-        dtype=[np.uint8, np.uint16, np.float32, np.float64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64,
+               np.float32, np.float64])
 
     # project image along the z axis
     projected_image = image.max(axis=0)
@@ -61,7 +62,8 @@ def mean_projection(image, return_float=False):
     check_array(
         image,
         ndim=3,
-        dtype=[np.uint8, np.uint16, np.float32, np.float64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64,
+               np.float32, np.float64])
 
     # project image along the z axis
     if return_float:
@@ -91,7 +93,8 @@ def median_projection(image):
     check_array(
         image,
         ndim=3,
-        dtype=[np.uint8, np.uint16, np.float32, np.float64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64,
+               np.float32, np.float64])
 
     # project image along the z axis
     projected_image = np.median(image, axis=0)
@@ -100,8 +103,11 @@ def median_projection(image):
     return projected_image
 
 
-def focus_projection(image, proportion=0.75, neighborhood_size=7,
-                     method="median"):
+def focus_projection(
+        image,
+        proportion=0.75,
+        neighborhood_size=7,
+        method="median"):
     """Project the z-dimension of an image.
 
     Inspired from Samacoits Aubin's thesis (part 5.3, strategy 5). Compare to
@@ -137,7 +143,8 @@ def focus_projection(image, proportion=0.75, neighborhood_size=7,
     check_array(
         image,
         ndim=3,
-        dtype=[np.uint8, np.uint16, np.float32, np.float64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64,
+               np.float32, np.float64])
 
     # compute focus measure for each pixel
     focus = compute_focus(image, neighborhood_size)
@@ -247,7 +254,8 @@ def in_focus_selection(image, focus, proportion):
     check_array(
         image,
         ndim=3,
-        dtype=[np.uint8, np.uint16, np.float32, np.float64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64,
+               np.float32, np.float64])
 
     # select and keep best z-slices
     indices_to_keep = get_in_focus_indices(focus, proportion)
@@ -263,7 +271,7 @@ def get_in_focus_indices(focus, proportion):
 
     Parameters
     ----------
-    focus : np.ndarray, np.float64
+    focus : np.ndarray, np.float
         A 3-d tensor with a focus metric computed for each pixel of the
         original image. See :func:`bigfish.stack.compute_focus`.
     proportion : float or int
@@ -278,7 +286,7 @@ def get_in_focus_indices(focus, proportion):
     """
     # check parameters
     check_parameter(proportion=(float, int))
-    check_array(focus, ndim=3, dtype=np.float64)
+    check_array(focus, ndim=3, dtype=[np.float32, np.float64])
     if isinstance(proportion, float) and 0 <= proportion <= 1:
         n = int(focus.shape[0] * proportion)
     elif isinstance(proportion, int) and 0 <= proportion:
diff --git a/bigfish/stack/quality.py b/bigfish/stack/quality.py
index b47d4d7..53b82f6 100644
--- a/bigfish/stack/quality.py
+++ b/bigfish/stack/quality.py
@@ -50,7 +50,8 @@ def compute_focus(image, neighborhood_size=31):
     check_array(
         image,
         ndim=[2, 3],
-        dtype=[np.uint8, np.uint16, np.float32, np.float64])
+        dtype=[np.uint8, np.uint16, np.int32, np.int64,
+               np.float32, np.float64])
     check_parameter(neighborhood_size=(int, tuple, list))
     if (isinstance(neighborhood_size, (tuple, list))
             and len(neighborhood_size) != 2):
@@ -61,7 +62,7 @@ def compute_focus(image, neighborhood_size=31):
                          .format(len(neighborhood_size)))
 
     # cast image in float if necessary
-    if image.dtype in [np.uint8, np.uint16]:
+    if image.dtype in [np.uint8, np.uint16, np.int32, np.int64]:
         image_float = image.astype(np.float64)
     else:
         image_float = image
@@ -89,7 +90,7 @@ def _compute_focus_3d(image_3d, kernel_size):
 
     Returns
     -------
-    focus : np.ndarray, np.float64
+    focus : np.ndarray, np.float
         A 3-d tensor with the R(z, y, x) computed for each pixel of the
         original image.
 
@@ -101,7 +102,7 @@ def _compute_focus_3d(image_3d, kernel_size):
         focus.append(focus_2d)
 
     #  stack focus metrics
-    focus = np.stack(focus)
+    focus = np.stack(focus).astype(image_3d.dtype)
 
     return focus
 
@@ -120,7 +121,7 @@ def _compute_focus_2d(image_2d, kernel_size):
 
     Returns
     -------
-    focus : np.ndarray, np.float64
+    focus : np.ndarray, np.float
         A 2-d tensor with the R(y, x) computed for each pixel of the original
         image.
 
@@ -132,8 +133,8 @@ def _compute_focus_2d(image_2d, kernel_size):
         image_filtered_mean = mean_filter(image_2d, "rectangle", kernel_size)
 
     # compute focus metric
-    ratio_default_1 = np.ones_like(image_2d, dtype=np.float64)
-    ratio_default_2 = np.ones_like(image_filtered_mean, dtype=np.float64)
+    ratio_default_1 = np.ones_like(image_2d)
+    ratio_default_2 = np.ones_like(image_filtered_mean)
     ratio_1 = np.divide(
         image_2d, image_filtered_mean,
         out=ratio_default_1,
@@ -144,4 +145,7 @@ def _compute_focus_2d(image_2d, kernel_size):
         where=image_2d > 0)
     focus = np.where(image_2d >= image_filtered_mean, ratio_1, ratio_2)
 
+    # cast focus dtype (np.float32 or np.float64)
+    focus = focus.astype(image_2d.dtype)
+
     return focus
diff --git a/bigfish/stack/utils.py b/bigfish/stack/utils.py
index dcf2851..4a6b8e9 100644
--- a/bigfish/stack/utils.py
+++ b/bigfish/stack/utils.py
@@ -160,7 +160,6 @@ def _check_dtype_array(array, dtype):
     if isinstance(dtype, type):
         dtype = [dtype]
 
-    # TODO simplify
     # check the dtype of the array
     error = True
     for dtype_expected in dtype:
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..288923e
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,5 @@
+# Documentation for Big-FISH
+
+[![Documentation Status](https://readthedocs.org/projects/big-fish/badge/?version=stable)](https://big-fish.readthedocs.io/en/latest/?badge=stable)
+
+This folder gathers the materials for the online [documentation](https://big-fish.readthedocs.io/en/stable/).
diff --git a/docs/source/plot/plot_coordinate.rst b/docs/source/plot/plot_coordinate.rst
index 86de745..867e041 100644
--- a/docs/source/plot/plot_coordinate.rst
+++ b/docs/source/plot/plot_coordinate.rst
@@ -7,4 +7,8 @@ Single-cell plot
 
 Function to visualize coordinate representation of individual cells:
 
+* :func:`bigfish.plot.plot_cell`
+* :func:`bigfish.plot.plot_cell_coordinates`
+
 .. autofunction:: plot_cell
+.. autofunction:: plot_cell_coordinates
diff --git a/docs/source/utils/utils.rst b/docs/source/utils/utils.rst
index e9a4d57..41f38e4 100644
--- a/docs/source/utils/utils.rst
+++ b/docs/source/utils/utils.rst
@@ -72,6 +72,17 @@ Convert pixels and nanometers
 
 ------------
 
+Extract a spot image
+====================
+
+* :func:`bigfish.detection.get_spot_volume`
+* :func:`bigfish.detection.get_spot_surface`
+
+.. autofunction:: get_spot_volume
+.. autofunction:: get_spot_surface
+
+------------
+
 Format and save plots
 =====================
 
diff --git a/requirements.txt b/requirements.txt
index 74c7fa7..3e97e58 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
 numpy >= 1.16.0
-scikit-learn >= 0.21.0
+scikit-learn >= 0.24.0
 scikit-image >= 0.14.2
 scipy >= 1.4.1
 matplotlib >= 3.0.2


Test patch:
diff --git a/bigfish/detection/tests/test_utils.py b/bigfish/detection/tests/test_utils.py
index e115147..f9a028a 100644
--- a/bigfish/detection/tests/test_utils.py
+++ b/bigfish/detection/tests/test_utils.py
@@ -10,5 +10,7 @@
 # TODO add test for bigfish.detection.get_object_radius_pixel
 # TODO add test for bigfish.detection.get_object_radius_nm
 # TODO add test for bigfish.detection.build_reference_spot
+# TODO add test for bigfish.detection.get_spot_volume
+# TODO add test for bigfish.detection.get_spot_surface
 # TODO add test for bigfish.detection.compute_snr_spots
 # TODO add test for bigfish.detection.get_breaking_point
diff --git a/bigfish/multistack/tests/test_postprocess.py b/bigfish/multistack/tests/test_postprocess.py
index cb9e21e..2574aa7 100644
--- a/bigfish/multistack/tests/test_postprocess.py
+++ b/bigfish/multistack/tests/test_postprocess.py
@@ -22,9 +22,9 @@
 
 @pytest.mark.parametrize("ndim", [2, 3])
 @pytest.mark.parametrize("mask_dtype", [
-    np.uint8, np.uint16, np.int64, bool])
+    np.uint8, np.uint16, np.int32, np.int64, bool])
 @pytest.mark.parametrize("spot_dtype", [
-    np.int64, np.float64])
+    np.float32, np.float64, np.int32, np.int64])
 def test_identify_objects_in_region(ndim, mask_dtype, spot_dtype):
     # simulate mask and coordinates
     mask = np.zeros((10, 10), dtype=mask_dtype)
@@ -49,9 +49,9 @@ def test_identify_objects_in_region(ndim, mask_dtype, spot_dtype):
 
 @pytest.mark.parametrize("ndim", [2, 3])
 @pytest.mark.parametrize("mask_dtype", [
-    np.uint8, np.uint16, np.int64, bool])
+    np.uint8, np.uint16, np.int32, np.int64, bool])
 @pytest.mark.parametrize("spot_dtype", [
-    np.int64, np.float64])
+    np.float32, np.float64, np.int32, np.int64])
 def test_remove_transcription_site(ndim, mask_dtype, spot_dtype):
     # simulate mask and coordinates
     nuc_mask = np.zeros((10, 10), dtype=mask_dtype)
diff --git a/bigfish/stack/tests/test_io.py b/bigfish/stack/tests/test_io.py
index f4392c2..1230813 100644
--- a/bigfish/stack/tests/test_io.py
+++ b/bigfish/stack/tests/test_io.py
@@ -120,7 +120,7 @@ def test_dv(dtype):
 
 
 @pytest.mark.parametrize("shape", [
-    (8, 8), (8, 8, 8), (8, 8, 8, 8), (8, 8, 8, 8, 8)])
+    (8,), (8, 8), (8, 8, 8), (8, 8, 8, 8), (8, 8, 8, 8, 8)])
 @pytest.mark.parametrize("dtype", [
     np.uint8, np.uint16, np.uint32, np.uint64,
     np.int8, np.int16, np.int32, np.int64,
diff --git a/bigfish/stack/tests/test_projection.py b/bigfish/stack/tests/test_projection.py
index c4bebee..f9d7c34 100644
--- a/bigfish/stack/tests/test_projection.py
+++ b/bigfish/stack/tests/test_projection.py
@@ -80,7 +80,7 @@
 # ### test 2-d projection ###
 
 @pytest.mark.parametrize("dtype", [
-    np.uint8, np.uint16, np.float32, np.float64])
+    np.uint8, np.uint16, np.int32, np.int64, np.float32, np.float64])
 def test_maximum_projection(dtype):
     x = x_3d.astype(dtype)
     expected_y = np.array([[3, 0, 0, 0, 0],
@@ -94,7 +94,7 @@ def test_maximum_projection(dtype):
 
 
 @pytest.mark.parametrize("dtype", [
-    np.uint8, np.uint16, np.float32, np.float64])
+    np.uint8, np.uint16, np.int32, np.int64, np.float32, np.float64])
 def test_mean_projection(dtype):
     # 'return_float' == False
     x = x_3d.astype(dtype)
@@ -119,7 +119,7 @@ def test_mean_projection(dtype):
 
 
 @pytest.mark.parametrize("dtype", [
-    np.uint8, np.uint16, np.float32, np.float64])
+    np.uint8, np.uint16, np.int32, np.int64, np.float32, np.float64])
 def test_median_projection(dtype):
     x = x_3d.astype(dtype)
     expected_y = np.array([[2, 0, 0, 0, 0],
@@ -215,7 +215,7 @@ def test_get_in_focus_indices():
 
 
 @pytest.mark.parametrize("dtype", [
-    np.uint8, np.uint16, np.float32, np.float64])
+    np.uint8, np.uint16, np.int32, np.int64, np.float32, np.float64])
 def test_in_focus_selection(dtype):
     x = x_3d_out_focus.astype(dtype)
     expected_y = x_3d.astype(dtype)
@@ -226,7 +226,7 @@ def test_in_focus_selection(dtype):
 
 
 @pytest.mark.parametrize("dtype", [
-    np.uint8, np.uint16, np.float32, np.float64])
+    np.uint8, np.uint16, np.int32, np.int64, np.float32, np.float64])
 def test_focus_projection(dtype):
     x = x_3d_out_focus.astype(dtype)
 
diff --git a/bigfish/stack/tests/test_quality.py b/bigfish/stack/tests/test_quality.py
index fe57efd..068a67d 100644
--- a/bigfish/stack/tests/test_quality.py
+++ b/bigfish/stack/tests/test_quality.py
@@ -52,7 +52,7 @@
 
 
 @pytest.mark.parametrize("dtype", [
-    np.uint8, np.uint16, np.float32, np.float64])
+    np.uint8, np.uint16, np.int32, np.int64, np.float32, np.float64])
 @pytest.mark.parametrize("neighborhood_size", [
     31, (5, 11), [11, 5]])
 def test_compute_focus_format(dtype, neighborhood_size):
@@ -60,7 +60,10 @@ def test_compute_focus_format(dtype, neighborhood_size):
     image = np.random.normal(loc=0.0, scale=1.0, size=10000)
     image = np.reshape(image, (100, 100)).astype(dtype)
     focus = stack.compute_focus(image, neighborhood_size=neighborhood_size)
-    assert focus.dtype == np.float64
+    if dtype == np.float32:
+        assert focus.dtype == np.float32
+    else:
+        assert focus.dtype == np.float64
     assert focus.shape == image.shape
     assert focus.min() >= 1
 
@@ -68,7 +71,10 @@ def test_compute_focus_format(dtype, neighborhood_size):
     image = np.random.normal(loc=0.0, scale=1.0, size=100000)
     image = np.reshape(image, (10, 100, 100)).astype(dtype)
     focus = stack.compute_focus(image, neighborhood_size=neighborhood_size)
-    assert focus.dtype == np.float64
+    if dtype == np.float32:
+        assert focus.dtype == np.float32
+    else:
+        assert focus.dtype == np.float64
     assert focus.shape == image.shape
     assert focus.min() >= 1