Repository: nilearn/nilearn

Issue:
node_size does not work as array-like for nilearn.plotting.plot_markers for "r" and "l" directions
<!--Provide a brief description of the bug.-->
I think the nilearn.plotting.plot_markers function is not working as expected. Specifically when giving node size as an array-like it will not work for "r" and "l" directions because the marker_size length is not adjusted according to the relevant coordinates

<!--Please fill in the following information, to the best of your ability.-->
Nilearn version:
nilearn==0.8.1

### Expected behavior
each node should be sized according to node_size

### Actual behavior
It will work as expected for directions "y" and "z".
however this will not work for "l" and "r" display direction.

I think this is because in display.add_markers() under

```python
elif direction == 'l':
        relevant_coords = (xcoords <= 0)
        xdata = xdata[relevant_coords]
        ydata = ydata[relevant_coords]
```
you do not select the correct index from marker_size based on the relevant coordinates.

Traceback (most recent call last):
  File "04_plot_pareto_scores.py", line 92, in <module>
    brain = plotting.plot_markers(
  File "/home/leonard/.venvs/Gradient-Identification/lib/python3.8/site-packages/nilearn/plotting/img_plotting.py", line 1429, in plot_markers
    display.add_markers(
  File "/home/leonard/.venvs/Gradient-Identification/lib/python3.8/site-packages/nilearn/plotting/displays.py", line 1081, in add_markers
    display_ax.ax.scatter(xdata, ydata, s=marker_size,
  File "/home/leonard/.venvs/Gradient-Identification/lib/python3.8/site-packages/matplotlib/__init__.py", line 1361, in inner
    return func(ax, *map(sanitize_sequence, args), **kwargs)
  File "/home/leonard/.venvs/Gradient-Identification/lib/python3.8/site-packages/matplotlib/axes/_axes.py", line 4507, in scatter
    raise ValueError(
ValueError: s must be a scalar, or float array-like with the same size as x and y


### Steps and code to reproduce bug
The below code should reproduce the faulty behaviour.

It will do as desired for display mode "yz", but throw the beforementioned error for display mode "lyrz".

```python
#!/usr/bin/env python3

import matplotlib.pyplot as plt
from nilearn import plotting
from nilearn import datasets
import numpy as np

# get some coords
power = datasets.fetch_coords_power_2011()
coords = np.vstack((power.rois['x'], power.rois['y'], power.rois['z'])).T

# node strength
node_strength = np.random.rand(264,)
node_sizes = np.random.rand(264,)*50

brain = plotting.plot_markers(
    node_strength,
    coords,
    node_vmin=0,
    node_vmax=1,
    node_size=node_sizes,
    node_cmap = "rainbow",
    display_mode="lyrz"
)
plt.show()


```



Discussion:
Sorry, I have a hard time reproducing the bug on my box, but your your case is certainly valid... it looks like you have identified the fix. Can you open a PR ?
Best,
Yeah sure!

Resolving patch:
diff --git a/nilearn/plotting/displays.py b/nilearn/plotting/displays.py
--- a/nilearn/plotting/displays.py
+++ b/nilearn/plotting/displays.py
@@ -1053,6 +1053,7 @@ def add_markers(self, marker_coords, marker_color='r', marker_size=30,
             xdata, ydata = marker_coords_2d.T
 	        # Allow markers only in their respective hemisphere when appropriate
             marker_color_ = marker_color
+            marker_size_ = marker_size
             if direction in ('lr'):
                 if (not isinstance(marker_color, str) and
 	            not isinstance(marker_color, np.ndarray)):
@@ -1067,6 +1068,9 @@ def add_markers(self, marker_coords, marker_color='r', marker_size=30,
                 if (not isinstance(marker_color, str) and
                         len(marker_color) != 1):
                     marker_color_ = marker_color_[relevant_coords]
+                if not isinstance(marker_size, numbers.Number):
+                    marker_size_ = np.asarray(marker_size_)[relevant_coords]
+
             # Check if coord has integer represents a cut in direction
             # to follow the heuristic. If no foreground image is given
             # coordinate is empty or None. This case is valid for plotting
@@ -1078,7 +1082,7 @@ def add_markers(self, marker_coords, marker_color='r', marker_size=30,
                 mask = np.abs(third_d - coord) <= 2.
                 xdata = xdata[mask]
                 ydata = ydata[mask]
-            display_ax.ax.scatter(xdata, ydata, s=marker_size,
+            display_ax.ax.scatter(xdata, ydata, s=marker_size_,
                                   c=marker_color_, **kwargs)
 
     def annotate(self, left_right=True, positions=True, scalebar=False,


Test patch:
diff --git a/nilearn/plotting/tests/test_img_plotting.py b/nilearn/plotting/tests/test_img_plotting.py
--- a/nilearn/plotting/tests/test_img_plotting.py
+++ b/nilearn/plotting/tests/test_img_plotting.py
@@ -1479,6 +1479,19 @@ def test_plot_markers(tmpdir):
     plt.close()
     plot_markers(*args, node_size=np.array([10, 20, 30, 40]), **kwargs)
     plt.close()
+    node_sizes = np.array([10, 20, 30, 40])
+    display = plot_markers(*args, display_mode="lyrz", node_size=node_sizes)
+    for d, axes in display.axes.items():
+        display_sizes = axes.ax.collections[0].get_sizes()
+        if d == 'l':
+            expected_sizes = node_sizes[-2:]
+        elif d == 'r':
+            expected_sizes = node_sizes[:-2]
+        else:
+            expected_sizes = node_sizes
+        assert np.all(display_sizes == expected_sizes)
+    plt.close()
+
 
     # Different options for cmap related arguments
     plot_markers(*args, node_cmap='RdBu', node_vmin=0, **kwargs)