Repository: silx-kit/silx
Issue: [scatter plot] Regular grid breaks the plot in some cases

With Flint, my scan simulator is able to produce data that can break the scatter item.

Yet, I did not try to reproduce the result with silx.

I used axis X and axis Y with the same array (210 points for both, same as the value array)

That's problematic cause after that the plot is not anymore working.

Other visualizations, like irregular grid or interpolation display things or nothing, but do not fail the plot.

That's blocking for me cause, it's easy to reproduce by clicking on all by buttons, for example, to swap X and Y axis, you have pass by a state where both axis point to the same data.

```
CRITICAL:root:Uncaught exception
Traceback (most recent call last):
  File "/users/valls/Software/miniconda3/envs/blissenv/lib/python3.7/site-packages/silx/gui/plot/backends/BackendBase.py", line 361, in postRedisplay
    plot.replot()
  File "/users/valls/Software/miniconda3/envs/blissenv/lib/python3.7/site-packages/silx/gui/plot/PlotWidget.py", line 2713, in replot
    item._update(self._backend)
  File "/users/valls/Software/miniconda3/envs/blissenv/lib/python3.7/site-packages/silx/gui/plot/items/core.py", line 319, in _update
    self._backendRenderer = self._addBackendRenderer(backend)
  File "/users/valls/Software/miniconda3/envs/blissenv/lib/python3.7/site-packages/silx/gui/plot/items/scatter.py", line 453, in _addBackendRenderer
    image[:len(rgbacolors)] = rgbacolors
ValueError: could not broadcast input array from shape (210,4) into shape (196,4)
```

Changed files:
silx/gui/plot/items/scatter.py

diff --git a/silx/gui/plot/items/scatter.py b/silx/gui/plot/items/scatter.py
index da478b27e..30f30444e 100644
--- a/silx/gui/plot/items/scatter.py
+++ b/silx/gui/plot/items/scatter.py
@@ -142,12 +142,13 @@ def is_monotonic(array):
     :rtype: int
     """
     diff = numpy.diff(numpy.ravel(array))
-    if numpy.all(diff >= 0):
-        return 1
-    elif numpy.all(diff <= 0):
-        return -1
-    else:
-        return 0
+    with numpy.errstate(invalid='ignore'):
+        if numpy.all(diff >= 0):
+            return 1
+        elif numpy.all(diff <= 0):
+            return -1
+        else:
+            return 0
 
 
 def _guess_grid(x, y):
@@ -345,6 +346,18 @@ class Scatter(PointsBase, ColormapMixIn, ScatterVisualizationMixIn):
                 if order is None:
                     order = guess[0]
 
+            nbpoints = len(self.getXData(copy=False))
+            if nbpoints > shape[0] * shape[1]:
+                # More data points that provided grid shape: enlarge grid
+                _logger.warning(
+                    "More data points than provided grid shape size: extends grid")
+                dim0, dim1 = shape
+                if order == 'row':  # keep dim1, enlarge dim0
+                    dim0 = nbpoints // dim1 + (1 if nbpoints % dim1 else 0)
+                else:  # keep dim0, enlarge dim1
+                    dim1 = nbpoints // dim0 + (1 if nbpoints % dim0 else 0)
+                shape = dim0, dim1
+
             bounds = self.getVisualizationParameter(
                 self.VisualizationParameter.GRID_BOUNDS)
             if bounds is None:
@@ -393,14 +406,11 @@ class Scatter(PointsBase, ColormapMixIn, ScatterVisualizationMixIn):
         if self.__alpha is not None:
             rgbacolors[:, -1] = (rgbacolors[:, -1] * self.__alpha).astype(numpy.uint8)
 
-        # Apply mask to colors
-        rgbacolors = rgbacolors[mask]
-
         visualization = self.getVisualization()
 
         if visualization is self.Visualization.POINTS:
             return backend.addCurve(xFiltered, yFiltered,
-                                    color=rgbacolors,
+                                    color=rgbacolors[mask],
                                     symbol=self.getSymbol(),
                                     linewidth=0,
                                     linestyle="",
@@ -431,7 +441,7 @@ class Scatter(PointsBase, ColormapMixIn, ScatterVisualizationMixIn):
                     return backend.addTriangles(xFiltered,
                                                 yFiltered,
                                                 triangles,
-                                                color=rgbacolors,
+                                                color=rgbacolors[mask],
                                                 alpha=self.getAlpha())
 
             elif visualization is self.Visualization.REGULAR_GRID:
@@ -496,6 +506,7 @@ class Scatter(PointsBase, ColormapMixIn, ScatterVisualizationMixIn):
                 else:  # column-major order
                     y, x = coords[:, 0], coords[:, 1]
 
+                rgbacolors = rgbacolors[mask]  # Filter-out not finite points
                 gridcolors = numpy.empty(
                     (4 * nbpoints, rgbacolors.shape[-1]), dtype=rgbacolors.dtype)
                 for first in range(4):