Repository: mne-tools/mne-python

Issue:
Creation of Brain object should not require curv.*h file
### Description of the problem

Plotting a pial brain surface should only require the pial surface files. This is evident in the [mne freesurfer examples](https://mne.tools/stable/auto_tutorials/forward/50_background_freesurfer_mne.html#using-freesurfer-s-surface-reconstructions)

 Currently the initialization for the Brain object returns an error if missing a "curve.*h" file. 

### Steps to reproduce

```Python
from mne.viz import Brain

f = Brain(subject, subjects_dir=subjects_dir, cortex='low_contrast', alpha=0.5,
         background='grey', surf='pial')
```


### Link to data

_No response_

### Expected results

A plot of a brain

### Actual results

  File "C:\Users\ae166\git\SentenceRep_analysis\ieeg\viz\mri.py", line 312, in _
    f = Brain(sub, subjects_dir=subj_dir, cortex='low_contrast', alpha=0.5,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ae166\.conda\envs\ieeg\Lib\site-packages\mne\viz\_brain\_brain.py", line 425, in __init__
    geo.load_curvature()
  File "C:\Users\ae166\.conda\envs\ieeg\Lib\site-packages\mne\viz\_brain\surface.py", line 179, in load_curvature
    self.curv = read_curvature(curv_path, binary=False)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ae166\.conda\envs\ieeg\Lib\site-packages\mne\surface.py", line 815, in read_curvature
    with open(filepath, "rb") as fobj:
         ^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\ae166\\Box\\ECoG_Recon\\D28\\surf\\lh.curv

### Additional information

Platform             Windows-10-10.0.19044-SP0
Python               3.11.3 | packaged by Anaconda, Inc. | (main, Apr 19 2023, 23:46:34) [MSC v.1916 64 bit (AMD64)]
Executable           C:\Users\ae166\.conda\envs\ieeg\python.exe
CPU                  Intel64 Family 6 Model 158 Stepping 9, GenuineIntel (8 cores)
Memory               63.9 GB
Core
├☑ mne               1.4.0
├☑ numpy             1.24.3 (MKL 2023.1-Product with 4 threads)
├☑ scipy             1.10.1
├☑ matplotlib        3.7.1 (backend=TkAgg)
├☑ pooch             1.7.0
└☑ jinja2            3.1.2
Numerical (optional)
├☑ sklearn           1.2.2
├☑ numba             0.57.0
├☑ nibabel           5.1.0
├☑ dipy              1.7.0
├☑ pandas            2.0.1
└☐ unavailable       nilearn, openmeeg, cupy
Visualization (optional)
├☑ pyvista           0.39.1 (OpenGL 4.5.0 - Build 30.0.101.1692 via Intel(R) HD Graphics 630)
├☑ pyvistaqt         0.10.0
├☑ vtk               9.2.6
├☑ qtpy              2.3.1 (PyQt5=5.15.2)
└☐ unavailable       ipyvtklink, ipympl, pyqtgraph, mne-qt-browser
Ecosystem (optional)
├☑ mne-bids          0.12
└☐ unavailable       mne-nirs, mne-features, mne-connectivity, mne-icalabel, mne-bids-pipeline


Discussion:

Resolving patch:
diff --git a/mne/viz/_brain/_brain.py b/mne/viz/_brain/_brain.py
--- a/mne/viz/_brain/_brain.py
+++ b/mne/viz/_brain/_brain.py
@@ -433,8 +433,12 @@ def __init__(
                         normals=self.geo[h].nn,
                     )
                     mesh.map()  # send to GPU
+                    if self.geo[h].bin_curv is None:
+                        scalars = mesh._default_scalars[:, 0]
+                    else:
+                        scalars = self.geo[h].bin_curv
                     mesh.add_overlay(
-                        scalars=self.geo[h].bin_curv,
+                        scalars=scalars,
                         colormap=geo_kwargs["colormap"],
                         rng=[geo_kwargs["vmin"], geo_kwargs["vmax"]],
                         opacity=alpha,
diff --git a/mne/viz/_brain/surface.py b/mne/viz/_brain/surface.py
--- a/mne/viz/_brain/surface.py
+++ b/mne/viz/_brain/surface.py
@@ -175,12 +175,17 @@ def z(self):
     def load_curvature(self):
         """Load in curvature values from the ?h.curv file."""
         curv_path = path.join(self.data_path, "surf", "%s.curv" % self.hemi)
-        self.curv = read_curvature(curv_path, binary=False)
-        self.bin_curv = np.array(self.curv > 0, np.int64)
+        if path.isfile(curv_path):
+            self.curv = read_curvature(curv_path, binary=False)
+            self.bin_curv = np.array(self.curv > 0, np.int64)
+            color = (self.curv > 0).astype(float)
+        else:
+            self.curv = None
+            self.bin_curv = None
+            color = np.ones((self.coords.shape[0]))
         # morphometry (curvature) normalization in order to get gray cortex
         # TODO: delete self.grey_curv after cortex parameter
         # will be fully supported
-        color = (self.curv > 0).astype(float)
         color = 0.5 - (color - 0.5) / 3
         color = color[:, np.newaxis] * [1, 1, 1]
         self.grey_curv = color


Test patch:
diff --git a/mne/viz/_brain/tests/test_brain.py b/mne/viz/_brain/tests/test_brain.py
--- a/mne/viz/_brain/tests/test_brain.py
+++ b/mne/viz/_brain/tests/test_brain.py
@@ -424,26 +424,31 @@ def __init__(self):
     info["chs"][0]["coord_frame"] = 99
     with pytest.raises(RuntimeError, match='must be "meg", "head" or "mri"'):
         brain.add_sensors(info, trans=fname_trans)
+    brain.close()
 
     # test sEEG projection onto inflated
     # make temp path to fake pial surface
     os.makedirs(tmp_path / subject / "surf", exist_ok=True)
     for hemi in ("lh", "rh"):
-        # fake white surface for pial
+        # fake white surface for pial, and no .curv file
         copyfile(
             subjects_dir / subject / "surf" / f"{hemi}.white",
             tmp_path / subject / "surf" / f"{hemi}.pial",
         )
-        copyfile(
-            subjects_dir / subject / "surf" / f"{hemi}.curv",
-            tmp_path / subject / "surf" / f"{hemi}.curv",
-        )
         copyfile(
             subjects_dir / subject / "surf" / f"{hemi}.inflated",
             tmp_path / subject / "surf" / f"{hemi}.inflated",
         )
-
-    brain._subjects_dir = tmp_path
+    brain = Brain(
+        hemi=hemi,
+        surf=surf,
+        size=size,
+        title=title,
+        cortex=cortex,
+        units="m",
+        subject=subject,
+        subjects_dir=tmp_path,
+    )
     proj_info = create_info([f"Ch{i}" for i in range(1, 7)], 1000, "seeg")
     pos = (
         np.array(