diff --git a/extensions/chaeo/batch_jobs/20231023_Porto_4ch.py b/extensions/chaeo/batch_jobs/20231023_Porto_4ch.py
index 0d99fe5f5267d0ff6969235a4f44222ea478b5aa..1e263ddf8cb834fa0e416773a6adf6f5f6b5c234 100644
--- a/extensions/chaeo/batch_jobs/20231023_Porto_4ch.py
+++ b/extensions/chaeo/batch_jobs/20231023_Porto_4ch.py
@@ -22,19 +22,18 @@ if __name__ == '__main__':
 
     # write single-position TIF color stacks
     where_proc = Path(where_output) / 'proc'
-    # for pos in range(0, cf.shape[cf.axes.index('S')]):
+
+    for pos in range(0, cf.shape[cf.axes.index('S')]):
     # for pos in [0, 50, 100, 150, 200]:
-    #     fname = f'{czi_filepath.stem}_p{pos:02d}.tif'
-    #     write_accessor_data_to_file(
-    #         where_proc / fname,
-    #         get_accessor_from_multiposition_czi(cf, pos)
-    #     )
-    #     print(f'Wrote file {fname}')
+        fname = f'{czi_filepath.stem}_p{pos:04d}.tif'
+        write_accessor_data_to_file(
+            where_proc / fname,
+            get_accessor_from_multiposition_czi(cf, pos)
+        )
+        print(f'Wrote file {fname}')
 
     px_ilp = Path('c:/Users/rhodes/projects/proj0017-ehcfm-analysis/exp0001/ilastik/px_4ch_02.ilp').__str__()
 
-    where_proc = Path('c:/Users/rhodes/projects/proj0017-ehcfm-analysis/exp0001/output/batch-output-20240126-0003/proc')
-
     params = {
         'pxmap_threshold': 0.25,
         'pxmap_foreground_channel': 0,
@@ -55,6 +54,7 @@ if __name__ == '__main__':
         'rgb_overlay_channels': (1, None, None),
         'rgb_overlay_weights': (0.2, 1.0, 1.0),
         'draw_label_on_zstack': True,
+        'pxmap_use_all_channels': True,
     }
 
     input_files = get_matching_files(where_proc, 'tif', coord_filter={})
@@ -66,14 +66,13 @@ if __name__ == '__main__':
         [IlastikPixelClassifierModel(params={'project_file': Path(px_ilp)})],
         params,
         catch_and_continue=False,
-        chunk_size=25,
+        chunk_size=50,
     )
 
     write_ecotaxa_tsv_chunked_subdirectories(
         where_output,
         'workflow_data.csv',
         sample_id=sample_id,
-        scope_id='EMBL-MS-Zeiss-LSM900'
+        scope_id='EMBL-MS-Zeiss-LSM900',
     )
-
     print('Finished')
\ No newline at end of file
diff --git a/extensions/chaeo/workflows.py b/extensions/chaeo/workflows.py
index 3231ef6befc27cc21bbcb4e14d7db67c16907f79..6adf7a077395f331061754b3061a2f4a2c8af210 100644
--- a/extensions/chaeo/workflows.py
+++ b/extensions/chaeo/workflows.py
@@ -31,6 +31,7 @@ def get_zmask_meta(
     zmask_clip: int = None,
     zmask_filters: Dict = None,
     zmask_type: str = 'boxes',
+    pxmap_use_all_channels: bool = False,
     **kwargs,
 ) -> tuple:
     ti = Timer()
@@ -41,9 +42,15 @@ def get_zmask_meta(
     # MIP if no zmask z-index is given, then classify pixels
     if isinstance(zmask_zindex, int):
         assert 0 < zmask_zindex < stack.nz
-        zmask_data = stack.get_one_channel_data(channel=segmentation_channel).data[:, :, :, zmask_zindex]
+        if pxmap_use_all_channels:
+            zmask_data = stack.data[:, :, :, zmask_zindex]
+        else:
+            zmask_data = stack.get_one_channel_data(channel=segmentation_channel).data[:, :, :, zmask_zindex]
     else:
-        zmask_data = stack.get_one_channel_data(channel=segmentation_channel).data.max(axis=-1, keepdims=True)
+        if pxmap_use_all_channels:
+            zmask_data = stack.data.max(axis=-1, keepdims=True)
+        else:
+            zmask_data = stack.get_one_channel_data(channel=segmentation_channel).data.max(axis=-1, keepdims=True)
     if zmask_clip:
         zmask_data = rescale(zmask_data, zmask_clip)
     mip = InMemoryDataAccessor(
@@ -68,7 +75,8 @@ def get_zmask_meta(
     ti.click('generate_zmasks')
 
     # record pixel scale
-    df['pixel_scale_in_micrometers'] = float(stack.pixel_scale_in_micrometers.get('X'))
+    px_scale = stack.pixel_scale_in_micrometers.get('X')
+    df['pixel_scale_in_micrometers'] = float(px_scale) if px_scale is not None else None
 
     return ti, stack, fstem, obmask, pxmap, zmask, zmask_meta, df, interm
 
@@ -80,7 +88,7 @@ def export_patches_from_multichannel_zstack(
         models: List[Model],
         pxmap_threshold: float,
         pxmap_foreground_channel: int,
-        segmentation_channel: int,
+        segmentation_channel: int, # -1 to use all channels
         patches_channel: int,
         zmask_zindex: int = None,  # None for MIP,
         zmask_clip: int = None,
@@ -99,6 +107,7 @@ def export_patches_from_multichannel_zstack(
         export_patch_masks=True,
         rgb_overlay_channels=(None, None, None),
         rgb_overlay_weights=(1.0, 1.0, 1.0),
+        **kwargs,
 ) -> Dict:
     pixel_classifier = models[0]
 
@@ -113,6 +122,7 @@ def export_patches_from_multichannel_zstack(
         zmask_expand_box_by=zmask_expand_box_by,
         zmask_filters=zmask_filters,
         zmask_type=zmask_type,
+        **kwargs,
     )
 
     if export_pixel_probabilities:
diff --git a/tests/test_accessors.py b/tests/test_accessors.py
deleted file mode 100644
index 557970ea691b91b228a43e29993bc4068c8d88db..0000000000000000000000000000000000000000
--- a/tests/test_accessors.py
+++ /dev/null
@@ -1,118 +0,0 @@
-import unittest
-
-import numpy as np
-
-from conf.testing import czifile, output_path, monopngfile, rgbpngfile, tifffile, monozstackmask
-from model_server.accessors import CziImageFileAccessor, DataShapeError, generate_file_accessor, InMemoryDataAccessor, PngFileAccessor, write_accessor_data_to_file, TifSingleSeriesFileAccessor
-
-class TestCziImageFileAccess(unittest.TestCase):
-
-    def setUp(self) -> None:
-        pass
-
-    def test_tiffile_is_correct_shape(self):
-        tf = generate_file_accessor(tifffile['path'])
-
-        self.assertIsInstance(tf, TifSingleSeriesFileAccessor)
-        self.assertEqual(tf.shape_dict['Y'], tifffile['h'])
-        self.assertEqual(tf.shape_dict['X'], tifffile['w'])
-        self.assertEqual(tf.chroma, tifffile['c'])
-        self.assertTrue(tf.is_3d())
-        self.assertEqual(len(tf.data.shape), 4)
-        self.assertEqual(tf.shape[0], tifffile['h'])
-        self.assertEqual(tf.shape[1], tifffile['w'])
-
-    def test_czifile_is_correct_shape(self):
-        cf = CziImageFileAccessor(czifile['path'])
-        self.assertEqual(cf.shape_dict['Y'], czifile['h'])
-        self.assertEqual(cf.shape_dict['X'], czifile['w'])
-        self.assertEqual(cf.chroma, czifile['c'])
-        self.assertFalse(cf.is_3d())
-        self.assertEqual(len(cf.data.shape), 4)
-        self.assertEqual(cf.shape[0], czifile['h'])
-        self.assertEqual(cf.shape[1], czifile['w'])
-
-    def test_get_single_channel_from_zstack(self):
-        w = 256
-        h = 512
-        nc = 4
-        nz = 11
-        c = 3
-        cf = InMemoryDataAccessor(np.random.rand(h, w, nc, nz))
-        sc = cf.get_one_channel_data(c)
-        self.assertEqual(sc.shape, (h, w, 1, nz))
-
-    def test_write_single_channel_tif(self):
-        ch = 4
-        cf = CziImageFileAccessor(czifile['path'])
-        mono = cf.get_one_channel_data(ch)
-        self.assertTrue(
-            write_accessor_data_to_file(
-                output_path / f'{cf.fpath.stem}_ch{ch}.tif',
-                mono
-            )
-        )
-        self.assertEqual(cf.data.shape[0:2], mono.data.shape[0:2])
-        self.assertEqual(cf.data.shape[3], mono.data.shape[2])
-
-    def test_conform_data_shorter_than_xycz(self):
-        h = 256
-        w = 512
-        data = np.random.rand(h, w, 1)
-        acc = InMemoryDataAccessor(data)
-        self.assertEqual(
-            InMemoryDataAccessor.conform_data(data).shape,
-            (256, 512, 1, 1)
-        )
-        self.assertEqual(
-            acc.shape_dict,
-            {'Y': 256, 'X': 512, 'C': 1, 'Z': 1}
-        )
-
-    def test_conform_data_longer_than_xycz(self):
-        data = np.random.rand(256, 512, 12, 8, 3)
-        with self.assertRaises(DataShapeError):
-            acc = InMemoryDataAccessor(data)
-
-
-    def test_write_multichannel_image_preserve_axes(self):
-        h = 256
-        w = 512
-        c = 3
-        nz = 10
-
-        yxcz = (2**8 * np.random.rand(h, w, c, nz)).astype('uint8')
-        acc = InMemoryDataAccessor(yxcz)
-        fp = output_path / f'rand3d.tif'
-        self.assertTrue(
-            write_accessor_data_to_file(fp, acc)
-        )
-        # need to sort out x,y flipping since np convention yxcz flips axes in 3d tif
-        self.assertEqual(acc.shape_dict['X'], w, acc.shape_dict)
-        self.assertEqual(acc.shape_dict['Y'], h, acc.shape_dict)
-
-        # re-open file and check axes order
-        from tifffile import TiffFile
-        fh = TiffFile(fp)
-        self.assertEqual(len(fh.series), 1)
-        se = fh.series[0]
-        fh_shape_dict = {se.axes[i]: se.shape[i] for i in range(0, len(se.shape))}
-        self.assertEqual(fh_shape_dict, acc.shape_dict, 'Axes are not preserved in TIF output')
-
-    def test_read_png(self, pngfile=rgbpngfile):
-        acc = PngFileAccessor(pngfile['path'])
-        self.assertEqual(acc.hw, (pngfile['h'], pngfile['w']))
-        self.assertEqual(acc.chroma, pngfile['c'])
-        self.assertEqual(acc.nz, 1)
-
-    def test_read_mono_png(self):
-        return self.test_read_png(pngfile=monopngfile)
-
-    def test_read_zstack_mono_mask(self):
-        acc = generate_file_accessor(monozstackmask['path'])
-        self.assertTrue(acc.is_mask())
-
-    def test_read_in_pixel_scale_from_czi(self):
-        cf = CziImageFileAccessor(czifile['path'])
-        pxs = cf.pixel_scale_in_micrometers
-        self.assertAlmostEqual(pxs['X'], czifile['um_per_pixel'], places=3)
\ No newline at end of file