codecov-io: # [Codecov](https://codecov.io/gh/Project-MONAI/MONAI/pull/213?src=pr&el=h1) Report
> Merging [#213](https://codecov.io/gh/Project-MONAI/MONAI/pull/213?src=pr&el=desc) into [master](https://codecov.io/gh/Project-MONAI/MONAI/commit/65b8e566921776275a0fd74e81bc61c3b576a7f4&el=desc) will **increase** coverage by `0.02%`.
> The diff coverage is `94.28%`.

[![Impacted file tree graph](https://codecov.io/gh/Project-MONAI/MONAI/pull/213/graphs/tree.svg?width=650&height=150&src=pr&token=6FTC7U1JJ4)](https://codecov.io/gh/Project-MONAI/MONAI/pull/213?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #213      +/-   ##
==========================================
+ Coverage   87.98%   88.01%   +0.02%     
==========================================
  Files         126      126              
  Lines        5137     5147      +10     
==========================================
+ Hits         4520     4530      +10     
  Misses        617      617              
```


| [Impacted Files](https://codecov.io/gh/Project-MONAI/MONAI/pull/213?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [monai/transforms/composables.py](https://codecov.io/gh/Project-MONAI/MONAI/pull/213/diff?src=pr&el=tree#diff-bW9uYWkvdHJhbnNmb3Jtcy9jb21wb3NhYmxlcy5weQ==) | `97.22% <ø> (ø)` | |
| [monai/transforms/transforms.py](https://codecov.io/gh/Project-MONAI/MONAI/pull/213/diff?src=pr&el=tree#diff-bW9uYWkvdHJhbnNmb3Jtcy90cmFuc2Zvcm1zLnB5) | `94.15% <92.30%> (+0.07%)` | :arrow_up: |
| [tests/test\_load\_nifti.py](https://codecov.io/gh/Project-MONAI/MONAI/pull/213/diff?src=pr&el=tree#diff-dGVzdHMvdGVzdF9sb2FkX25pZnRpLnB5) | `96.15% <100.00%> (+0.50%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Project-MONAI/MONAI/pull/213?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Project-MONAI/MONAI/pull/213?src=pr&el=footer). Last update [65b8e56...376bc1c](https://codecov.io/gh/Project-MONAI/MONAI/pull/213?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

diff --git a/monai/transforms/composables.py b/monai/transforms/composables.py
index 6990df5f..88cebc41 100644
--- a/monai/transforms/composables.py
+++ b/monai/transforms/composables.py
@@ -115,10 +115,15 @@ class Orientationd(MapTransform):
 @alias('LoadNiftiD', 'LoadNiftiDict')
 class LoadNiftid(MapTransform):
     """
-    dictionary-based wrapper of LoadNifti, must load image and metadata together.
+    Dictionary-based wrapper of LoadNifti, must load image and metadata
+    together. If loading a list of files in one key, stack them together and
+    add a new dimension as the first dimension, and use the meta data of the
+    first image to represent the stacked result. Note that the affine transform
+    of all the stacked images should be same.
     """
 
-    def __init__(self, keys, as_closest_canonical=False, dtype=np.float32, meta_key_format='{}.{}', overwriting_keys=False):
+    def __init__(self, keys, as_closest_canonical=False, dtype=np.float32,
+                 meta_key_format='{}.{}', overwriting_keys=False):
         """
         Args:
             keys (hashable items): keys of the corresponding items to be transformed.
@@ -794,6 +799,7 @@ class RandRotated(Randomizable, MapTransform):
         cval (scalar): Value to fill outside boundary. Default: 0.
         prefiter (bool): Apply spline_filter before interpolation. Default: True.
     """
+
     def __init__(self, keys, degrees, prob=0.1, spatial_axes=(0, 1), reshape=True, order=1,
                  mode='constant', cval=0, prefilter=True):
         MapTransform.__init__(self, keys)
diff --git a/monai/transforms/transforms.py b/monai/transforms/transforms.py
index e3f76771..60aae8ba 100644
--- a/monai/transforms/transforms.py
+++ b/monai/transforms/transforms.py
@@ -139,7 +139,10 @@ class Orientation:
 @export
 class LoadNifti:
     """
-    Load Nifti format file from provided path.
+    Load Nifti format file or files from provided path. If loading a list of
+    files, stack them together and add a new dimension as first dimension, and
+    use the meta data of the first image to represent the stacked result. Note
+    that the affine transform of all the images should be same if ``image_only=False``.
     """
 
     def __init__(self, as_closest_canonical=False, image_only=False, dtype=np.float32):
@@ -162,34 +165,45 @@ class LoadNifti:
     def __call__(self, filename):
         """
         Args:
-            filename (str or file): path to file or file-like object.
+            filename (str, list, tuple, file): path file or file-like object or a list of files.
         """
-        img = nib.load(filename)
-        img = correct_nifti_header_if_necessary(img)
+        filename = ensure_tuple(filename)
+        img_array = list()
+        compatible_meta = dict()
+        for name in filename:
+            img = nib.load(name)
+            img = correct_nifti_header_if_necessary(img)
+            header = dict(img.header)
+            header['filename_or_obj'] = name
+            header['original_affine'] = img.affine
+            header['affine'] = img.affine
+            header['as_closest_canonical'] = self.as_closest_canonical
 
-        header = dict(img.header)
-        header['filename_or_obj'] = filename
-        header['original_affine'] = img.affine
-        header['affine'] = img.affine
-        header['as_closest_canonical'] = self.as_closest_canonical
+            if self.as_closest_canonical:
+                img = nib.as_closest_canonical(img)
+                header['affine'] = img.affine
 
-        if self.as_closest_canonical:
-            img = nib.as_closest_canonical(img)
-            header['affine'] = img.affine
+            img_array.append(np.array(img.get_fdata(dtype=self.dtype)))
+            img.uncache()
+
+            if self.image_only:
+                continue
 
-        data = np.array(img.get_fdata(dtype=self.dtype))
-        img.uncache()
+            if not compatible_meta:
+                for meta_key in header:
+                    meta_datum = header[meta_key]
+                    if type(meta_datum).__name__ == 'ndarray' \
+                            and np_str_obj_array_pattern.search(meta_datum.dtype.str) is not None:
+                        continue
+                    compatible_meta[meta_key] = meta_datum
+            else:
+                assert np.allclose(header['affine'], compatible_meta['affine']), \
+                    'affine data of all images should be same.'
 
+        img_array = np.stack(img_array, axis=0) if len(img_array) > 1 else img_array[0]
         if self.image_only:
-            return data
-        compatible_meta = dict()
-        for meta_key in header:
-            meta_datum = header[meta_key]
-            if type(meta_datum).__name__ == 'ndarray' \
-                    and np_str_obj_array_pattern.search(meta_datum.dtype.str) is not None:
-                continue
-            compatible_meta[meta_key] = meta_datum
-        return data, compatible_meta
+            return img_array
+        return img_array, compatible_meta
 
 
 @export

loading multiple modalities from separate files and combining the data arrays
**Is your feature request related to a problem? Please describe.**
currently loading multiple files are not supported by` LoadNifti` transform

**Describe the solution you'd like**
to load multiple image files and combine the data arrays, if meta data exist, could consider merging the meta data
diff --git a/tests/test_load_nifti.py b/tests/test_load_nifti.py
index de0660cc..644807a5 100644
--- a/tests/test_load_nifti.py
+++ b/tests/test_load_nifti.py
@@ -11,40 +11,60 @@
 
 import unittest
 import os
-import shutil
 import numpy as np
 import tempfile
 import nibabel as nib
 from parameterized import parameterized
 from monai.transforms.transforms import LoadNifti
 
-TEST_CASE_IMAGE_ONLY = [
+TEST_CASE_1 = [
     {
         'as_closest_canonical': False,
         'image_only': True
     },
+    ['test_image.nii.gz'],
     (128, 128, 128)
 ]
 
-TEST_CASE_IMAGE_METADATA = [
+TEST_CASE_2 = [
     {
         'as_closest_canonical': False,
         'image_only': False
     },
+    ['test_image.nii.gz'],
     (128, 128, 128)
 ]
 
+TEST_CASE_3 = [
+    {
+        'as_closest_canonical': False,
+        'image_only': True
+    },
+    ['test_image1.nii.gz', 'test_image2.nii.gz', 'test_image3.nii.gz'],
+    (3, 128, 128, 128)
+]
+
+TEST_CASE_4 = [
+    {
+        'as_closest_canonical': False,
+        'image_only': False
+    },
+    ['test_image1.nii.gz', 'test_image2.nii.gz', 'test_image3.nii.gz'],
+    (3, 128, 128, 128)
+]
+
 
 class TestLoadNifti(unittest.TestCase):
 
-    @parameterized.expand([TEST_CASE_IMAGE_ONLY, TEST_CASE_IMAGE_METADATA])
-    def test_shape(self, input_param, expected_shape):
+    @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_4])
+    def test_shape(self, input_param, filenames, expected_shape):
         test_image = np.random.randint(0, 2, size=[128, 128, 128])
         tempdir = tempfile.mkdtemp()
-        nib.save(nib.Nifti1Image(test_image, np.eye(4)), os.path.join(tempdir, 'test_image.nii.gz'))
-        test_data = os.path.join(tempdir, 'test_image.nii.gz')
-        result = LoadNifti(**input_param)(test_data)
-        shutil.rmtree(tempdir)
+        with tempfile.TemporaryDirectory() as tempdir:
+            for i, name in enumerate(filenames):
+                filenames[i] = os.path.join(tempdir, name)
+                nib.save(nib.Nifti1Image(test_image, np.eye(4)), filenames[i])
+            result = LoadNifti(**input_param)(filenames)
         if isinstance(result, tuple):
             result = result[0]
         self.assertTupleEqual(result.shape, expected_shape)
diff --git a/tests/test_load_niftid.py b/tests/test_load_niftid.py
index 071972f0..4393f1f2 100644
--- a/tests/test_load_niftid.py
+++ b/tests/test_load_niftid.py
@@ -11,7 +11,6 @@
 
 import unittest
 import os
-import shutil
 import numpy as np
 import tempfile
 import nibabel as nib
@@ -36,11 +35,11 @@ class TestLoadNiftid(unittest.TestCase):
         test_image = nib.Nifti1Image(np.random.randint(0, 2, size=[128, 128, 128]), np.eye(4))
         tempdir = tempfile.mkdtemp()
         test_data = dict()
-        for key in KEYS:
-            nib.save(test_image, os.path.join(tempdir, key + '.nii.gz'))
-            test_data.update({key: os.path.join(tempdir, key + '.nii.gz')})
-        result = LoadNiftid(**input_param)(test_data)
-        shutil.rmtree(tempdir)
+        with tempfile.TemporaryDirectory() as tempdir:
+            for key in KEYS:
+                nib.save(test_image, os.path.join(tempdir, key + '.nii.gz'))
+                test_data.update({key: os.path.join(tempdir, key + '.nii.gz')})
+            result = LoadNiftid(**input_param)(test_data)
         for key in KEYS:
             self.assertTupleEqual(result[key].shape, expected_shape)
 

pip install -e .[all]
parse_log_pytest
requirements.txt
pytest black flake8 mypy pytype
apt-get update apt-get install -y gcc
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
absl-py==1.4.0
attrs==22.2.0
black==22.8.0
cachetools==4.2.4
certifi==2021.5.30
charset-normalizer==2.0.12
click==8.0.4
coverage==6.2
cycler==0.11.0
dataclasses==0.8
decorator==4.4.2
flake8==5.0.4
google-auth==2.22.0
google-auth-oauthlib==0.4.6
grpcio==1.48.2
idna==3.10
imageio==2.15.0
importlab==0.8.1
importlib-metadata==4.8.3
iniconfig==1.1.1
kiwisolver==1.3.1
libcst==0.4.1
Markdown==3.3.7
matplotlib==3.3.4
mccabe==0.7.0
-e git+https://github.com/Project-MONAI/MONAI.git@434feb79017207d8e62a33ca8d0bcdb069c29f3c#egg=monai
mypy==0.971
mypy-extensions==1.0.0
networkx==2.5.1
nibabel==3.2.2
ninja==1.11.1.1
numpy==1.19.5
oauthlib==3.2.2
packaging==21.3
parameterized==0.8.1
pathspec==0.9.0
Pillow==8.4.0
platformdirs==2.4.0
pluggy==1.0.0
protobuf==3.19.6
py==1.11.0
pyasn1==0.5.1
pyasn1-modules==0.3.0
pycodestyle==2.9.1
pyflakes==2.5.0
pyparsing==3.1.4
pytest==7.0.1
python-dateutil==2.9.0.post0
pytorch-ignite==0.3.0
pytype==2022.1.5
PyWavelets==1.1.1
PyYAML==6.0.1
requests==2.27.1
requests-oauthlib==2.0.0
rsa==4.9
scikit-image==0.17.2
scipy==1.5.4
six==1.17.0
tabulate==0.8.10
tensorboard==2.10.1
tensorboard-data-server==0.6.1
tensorboard-plugin-wit==1.8.1
tifffile==2020.9.3
toml==0.10.2
tomli==1.2.3
torch==1.10.2
typed-ast==1.5.5
typing-inspect==0.9.0
typing_extensions==4.1.1
urllib3==1.26.20
Werkzeug==2.0.3
zipp==3.6.0

name: MONAI
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - absl-py==1.4.0
      - attrs==22.2.0
      - black==22.8.0
      - cachetools==4.2.4
      - charset-normalizer==2.0.12
      - click==8.0.4
      - coverage==6.2
      - cycler==0.11.0
      - dataclasses==0.8
      - decorator==4.4.2
      - flake8==5.0.4
      - google-auth==2.22.0
      - google-auth-oauthlib==0.4.6
      - grpcio==1.48.2
      - idna==3.10
      - imageio==2.15.0
      - importlab==0.8.1
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - kiwisolver==1.3.1
      - libcst==0.4.1
      - markdown==3.3.7
      - matplotlib==3.3.4
      - mccabe==0.7.0
      - mypy==0.971
      - mypy-extensions==1.0.0
      - networkx==2.5.1
      - nibabel==3.2.2
      - ninja==1.11.1.1
      - numpy==1.19.5
      - oauthlib==3.2.2
      - packaging==21.3
      - parameterized==0.8.1
      - pathspec==0.9.0
      - pillow==8.4.0
      - platformdirs==2.4.0
      - pluggy==1.0.0
      - protobuf==3.19.6
      - py==1.11.0
      - pyasn1==0.5.1
      - pyasn1-modules==0.3.0
      - pycodestyle==2.9.1
      - pyflakes==2.5.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - python-dateutil==2.9.0.post0
      - pytorch-ignite==0.3.0
      - pytype==2022.1.5
      - pywavelets==1.1.1
      - pyyaml==6.0.1
      - requests==2.27.1
      - requests-oauthlib==2.0.0
      - rsa==4.9
      - scikit-image==0.17.2
      - scipy==1.5.4
      - six==1.17.0
      - tabulate==0.8.10
      - tensorboard==2.10.1
      - tensorboard-data-server==0.6.1
      - tensorboard-plugin-wit==1.8.1
      - tifffile==2020.9.3
      - toml==0.10.2
      - tomli==1.2.3
      - torch==1.10.2
      - typed-ast==1.5.5
      - typing-extensions==4.1.1
      - typing-inspect==0.9.0
      - urllib3==1.26.20
      - werkzeug==2.0.3
      - zipp==3.6.0
prefix: /opt/conda/envs/MONAI

tests/test_load_nifti.py::TestLoadNifti::test_shape_0 tests/test_load_nifti.py::TestLoadNifti::test_shape_1 tests/test_load_nifti.py::TestLoadNifti::test_shape_2 tests/test_load_nifti.py::TestLoadNifti::test_shape_3
tests/test_load_niftid.py::TestLoadNiftid::test_shape_0
monai/transforms/transforms.py monai/transforms/composables.py
monai/transforms/transforms.py monai/transforms/composables.py