Repository: mne-tools/mne-python

Issue:
mne.stc_near_sensors options desciption
Hello,

If I understood different options of mne.stc_near_sensors correctly, I was wondering if in the documentation:

'sum'
    Activation is the sum across each sensor weighted by the fractional distance from each sensor. A sensor with zero distance gets weight 1 and a sensor at distance meters away (or larger) gets weight 0. If distance is less than the distance between any two electrodes, this will be the same as 'nearest'.

should be:


'sum'
    Activation is the sum across each sensor weighted by the fractional distance from each sensor. A sensor with zero distance gets weight 1 and a sensor at distance meters away (or larger) gets weight 0. If distance is less than **half** the distance between any two electrodes, this will be the same as **'single'**.





Discussion:
Have you checked the code @chapochn ? Or maybe tried a case for example where a source is 1mm away from one sensor and 9mm away from another (i.e., less than half the distance) to see if it indeed only gets values from one electrode or if it gets 90% from the first and 10% from the second?
Yes, the code and what I tried seem to support that.

What seems sure, is for "nearest", the sources gets the value of sensor **without** any decreases with distance (the line `vals = w[range_, idx] if mode == 'single' else 1.` in the code below), whereas for "sum" and "single", the value decreases with distance (the line `w = np.maximum(1. - dists[vertices] / distance, 0)`). And when we use "single", only the nearest sensor is used (`idx = np.argmax(w, axis=1)`). So "sum" behaves like "single" at a given source only when one or less sensors are within _distance_. But for "sum" and "single" to be the same on a global scale, no point should at a distance smaller than _distance_ from more than 1 sensor. If 2 sources are separated by a distance _distance_, a point between them would be influenced by both sources (because both sources would be at a distance smaller than _distance_). So sources need to be at least 2 _distance_ away. Or _distance_ should be half the minimal distance between sensors/electrodes, so that no "sphere of influence" overlap.


This is the relevant code:

```
    vertices = np.where((dists <= distance).any(-1))[0]
    logger.info(f'    {len(vertices)} / {len(rrs)} non-zero vertices')
    w = np.maximum(1. - dists[vertices] / distance, 0)
    # now we triage based on mode
    if mode in ('single', 'nearest'):
        range_ = np.arange(w.shape[0])
        idx = np.argmax(w, axis=1)
        vals = w[range_, idx] if mode == 'single' else 1.
        w.fill(0)
        w[range_, idx] = vals
    elif mode == 'weighted':
        norms = w.sum(-1, keepdims=True)
        norms[norms == 0] = 1.
        w /= norms
    missing = np.where(~np.any(w, axis=0))[0]
    if len(missing):
        warn(f'Channel{_pl(missing)} missing in STC: '
             f'{", ".join(evoked.ch_names[mi] for mi in missing)}')

    nz_data = w @ evoked.data
```
You can try in out with (if you have some _raw_ that has a montage):


```
pos = raw.get_montage().get_positions()['ch_pos']

import scipy.spatial.distance as sdist
xyzs = np.array(list(pos.values()))
distances = sdist.cdist(xyzs, xyzs)

distances = distances + 10000*np.eye(len(distances))
min_dist_between_sensors = np.min(distances)
```

If you set the option _distance_=distance > min_dist_between_sensors/2, then the outputs of mne.stc_near_sensors with options _mode_='single' and _mode_='sum' are not the same. If you set  _distance_=distance <= min_dist_between_sensors/2, then the outputs with options 'single' and 'sum'  are the same.
Thanks for investigating, can you make a PR to fix the docstring? Thanks @chapochn !
Will do!

Resolving patch:
diff --git a/mne/source_estimate.py b/mne/source_estimate.py
--- a/mne/source_estimate.py
+++ b/mne/source_estimate.py
@@ -3253,7 +3253,7 @@ def stc_near_sensors(evoked, trans, subject, distance=0.01, mode='sum',
         .. versionchanged:: 0.24
            Added "weighted" option.
     project : bool
-        If True, project the electrodes to the nearest ``'pial`` surface
+        If True, project the sensors to the nearest ``'pial`` surface
         vertex before computing distances. Only used when doing a
         surface projection.
     %(subjects_dir)s
@@ -3295,11 +3295,11 @@ def stc_near_sensors(evoked, trans, subject, distance=0.01, mode='sum',
         Activation is the sum across each sensor weighted by the fractional
         ``distance`` from each sensor. A sensor with zero distance gets weight
         1 and a sensor at ``distance`` meters away (or larger) gets weight 0.
-        If ``distance`` is less than the distance between any two electrodes,
-        this will be the same as ``'nearest'``.
+        If ``distance`` is less than half the distance between any two
+        sensors, this will be the same as ``'single'``.
     - ``'single'``
-        Same as ``'sum'`` except that only the nearest electrode is used,
-        rather than summing across electrodes within the ``distance`` radius.
+        Same as ``'sum'`` except that only the nearest sensor is used,
+        rather than summing across sensors within the ``distance`` radius.
         As ``'nearest'`` for vertices with distance zero to the projected
         sensor.
     - ``'nearest'``
@@ -3386,7 +3386,7 @@ def stc_near_sensors(evoked, trans, subject, distance=0.01, mode='sum',
         f'Projecting data from {len(pos)} sensor{_pl(pos)} onto {len(rrs)} '
         f'{src.kind} vertices: {mode} mode')
     if project and src.kind == 'surface':
-        logger.info('    Projecting electrodes onto surface')
+        logger.info('    Projecting sensors onto surface')
         pos = _project_onto_surface(pos, dict(rr=rrs), project_rrs=True,
                                     method='nearest')[2]
 


Test patch: