Repository: NeurodataWithoutBorders/pynwb

Issue:
[Bug]: SpatialSeries.reference_frame should be optional
### What happened?

The [spec for `SpatialSeries`](https://github.com/NeurodataWithoutBorders/nwb-schema/blob/dev/core/nwb.behavior.yaml#L59-L62) says that the "reference_frame" dataset is optional. However, it is a required argument in pynwb to the `SpatialSeries` constructor. 

This is blocking a user from validating their NWB files for upload onto DANDI after creating them using MatNWB.

### Steps to Reproduce

```python
n/a
```


### Traceback

_No response_

### Operating System

Windows

### Python Executable

Conda

### Python Version

3.11

### Package Versions

_No response_

### Code of Conduct

- [X] I agree to follow this project's [Code of Conduct](https://github.com/NeurodataWithoutBorders/pynwb/blob/dev/.github/CODE_OF_CONDUCT.rst)
- [X] Have you checked the [Contributing](https://github.com/NeurodataWithoutBorders/pynwb/blob/dev/docs/CONTRIBUTING.rst) document?
- [X] Have you ensured this bug was not already [reported](https://github.com/NeurodataWithoutBorders/pynwb/issues)?

Discussion:
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/NeurodataWithoutBorders/pynwb/pull/1986?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NeurodataWithoutBorders) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 83.07%. Comparing base [(`e938202`)](https://app.codecov.io/gh/NeurodataWithoutBorders/pynwb/commit/e938202b257e44c5536dc35476d55aa98e57d18d?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NeurodataWithoutBorders) to head [(`fce356f`)](https://app.codecov.io/gh/NeurodataWithoutBorders/pynwb/commit/fce356f2ef13ae9de2be8525257b747355c12527?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NeurodataWithoutBorders).

> :exclamation:  There is a different number of reports uploaded between BASE (e938202) and HEAD (fce356f). Click for more details.
> 
> <details><summary>HEAD has 7 uploads less than BASE</summary>
>
>| Flag | BASE (e938202) | HEAD (fce356f) |
>|------|------|------|
>|unit|4|1|
>|integration|4|0|
></details>

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##              dev    #1986      +/-   ##
==========================================
- Coverage   91.87%   83.07%   -8.80%     
==========================================
  Files          27       27              
  Lines        2695     2695              
  Branches      703      703              
==========================================
- Hits         2476     2239     -237     
- Misses        145      359     +214     
- Partials       74       97      +23     
```

| [Flag](https://app.codecov.io/gh/NeurodataWithoutBorders/pynwb/pull/1986/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NeurodataWithoutBorders) | Coverage Δ | |
|---|---|---|
| [integration](https://app.codecov.io/gh/NeurodataWithoutBorders/pynwb/pull/1986/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NeurodataWithoutBorders) | `?` | |
| [unit](https://app.codecov.io/gh/NeurodataWithoutBorders/pynwb/pull/1986/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NeurodataWithoutBorders) | `83.07% <ø> (-0.26%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NeurodataWithoutBorders#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/NeurodataWithoutBorders/pynwb/pull/1986?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NeurodataWithoutBorders).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NeurodataWithoutBorders).


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 16e50465..9f627141 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
 
 ### Bug fixes
 - Fixed bug in how `ElectrodeGroup.__init__` validates its `position` argument. @oruebel [#1770](https://github.com/NeurodataWithoutBorders/pynwb/pull/1770)
+- Changed `SpatialSeries.reference_frame` from required to optional as specified in the schema. @rly [#1986](https://github.com/NeurodataWithoutBorders/pynwb/pull/1986)
 
 ## PyNWB 2.8.2 (September 9, 2024)
 
diff --git a/src/pynwb/behavior.py b/src/pynwb/behavior.py
index 1b307853..286ec43b 100644
--- a/src/pynwb/behavior.py
+++ b/src/pynwb/behavior.py
@@ -28,8 +28,8 @@ class SpatialSeries(TimeSeries):
                      'or 3 columns, which represent x, y, and z.')},
             {'name': 'bounds', 'type': list, 'shape': ((1, 2), (2, 2), (3, 2)), 'default': None,
              'doc': 'The boundary range (min, max) for each dimension of data.'},
-            {'name': 'reference_frame', 'type': str,   # required
-             'doc': 'description defining what the zero-position is'},
+            {'name': 'reference_frame', 'type': str,
+             'doc': 'description defining what the zero-position is', 'default': None},
             {'name': 'unit', 'type': str, 'doc': 'The base unit of measurement (should be SI unit)',
              'default': 'meters'},
             *get_docval(TimeSeries.__init__, 'conversion', 'resolution', 'timestamps', 'starting_time', 'rate',


Test patch:
diff --git a/tests/integration/hdf5/test_behavior.py b/tests/integration/hdf5/test_behavior.py
index d4b230bc..eb597444 100644
--- a/tests/integration/hdf5/test_behavior.py
+++ b/tests/integration/hdf5/test_behavior.py
@@ -15,3 +15,14 @@ class TestSpatialSeriesIO(AcquisitionH5IOMixin, TestCase):
             reference_frame='reference_frame',
             timestamps=[1., 2., 3.]
         )
+
+
+class TestSpatialSeriesMinIO(AcquisitionH5IOMixin, TestCase):
+
+    def setUpContainer(self):
+        """ Return the test TimeSeries to read/write """
+        return SpatialSeries(
+            name='test_sS',
+            data=np.ones((3, 2)),
+            timestamps=[1., 2., 3.]
+        )
diff --git a/tests/unit/test_behavior.py b/tests/unit/test_behavior.py
index 6bcf1a9e..be43eb8b 100644
--- a/tests/unit/test_behavior.py
+++ b/tests/unit/test_behavior.py
@@ -21,6 +21,15 @@ class SpatialSeriesConstructor(TestCase):
         self.assertEqual(sS.bounds, [(-1,1),(-1,1),(-1,1)])
         self.assertEqual(sS.reference_frame, 'reference_frame')
 
+    def test_init_minimum(self):
+        sS = SpatialSeries(
+            name='test_sS',
+            data=np.ones((3, 2)),
+            timestamps=[1., 2., 3.]
+        )
+        assert sS.bounds is None
+        assert sS.reference_frame is None
+
     def test_set_unit(self):
         sS = SpatialSeries(
             name='test_sS',