Repository: pyqtgraph/pyqtgraph

Issue:
Pressing ROI on ImageView example causes unhandled exceptions
### Short description

When running the ImageView example, press the ROI button, and unhandled exceptions are generated.

### Code to reproduce

```bash
python -m pyqtgraph.examples
```
Select ImageView
Press ROI button

### Expected behavior
No unhandled exceptions

### Real behavior
Terminal starts spewing output

```
Traceback (most recent call last):
  File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/imageview/ImageView.py", line 566, in roiClicked
    self.roiChanged()
  File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/imageview/ImageView.py", line 640, in roiChanged
    self.roiCurves[i].setData(x, y, pen=p)
  File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotDataItem.py", line 471, in setData
    self.updateItems()
  File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotDataItem.py", line 497, in updateItems
    self.curve.setData(x=x, y=y, **curveArgs)
  File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 335, in setData
    self.updateData(*args, **kargs)
  File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 385, in updateData
    raise Exception("X and Y arrays must be the same shape--got %s and %s." % (self.xData.shape, self.yData.shape))
Exception: X and Y arrays must be the same shape--got (100,) and (10,).
[22:13:37]  Ignored exception:

    |==============================>>
    |  Traceback (most recent call last):
    |    File "/Users/ogi/Developer/pyqtgraph/examples/ImageView.py", line 70, in <module>
    |      QtGui.QApplication.instance().exec_()
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/widgets/GraphicsView.py", line 155, in paintEvent
    |      return QtGui.QGraphicsView.paintEvent(self, ev)
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/debug.py", line 93, in w
    |      printExc('Ignored exception:')
    |    --- exception caught here ---
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/debug.py", line 91, in w
    |      func(*args, **kwds)
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 464, in paint
    |      path = self.getPath()
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 446, in getPath
    |      self.path = self.generatePath(*self.getData())
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 435, in generatePath
    |      path = fn.arrayToQPath(x, y, connect=self.opts['connect'])
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/functions.py", line 1496, in arrayToQPath
    |      arr[1:-1]['y'] = y
    |  ValueError: could not broadcast input array from shape (10) into shape (100)
    |==============================<<
[22:13:37]  Ignored exception:

    |==============================>>
    |  Traceback (most recent call last):
    |    File "/Users/ogi/Developer/pyqtgraph/examples/ImageView.py", line 70, in <module>
    |      QtGui.QApplication.instance().exec_()
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/widgets/GraphicsView.py", line 155, in paintEvent
    |      return QtGui.QGraphicsView.paintEvent(self, ev)
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/debug.py", line 93, in w
    |      printExc('Ignored exception:')
    |    --- exception caught here ---
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/debug.py", line 91, in w
    |      func(*args, **kwds)
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 464, in paint
    |      path = self.getPath()
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 446, in getPath
    |      self.path = self.generatePath(*self.getData())
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 435, in generatePath
    |      path = fn.arrayToQPath(x, y, connect=self.opts['connect'])
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/functions.py", line 1496, in arrayToQPath
    |      arr[1:-1]['y'] = y
    |  ValueError: could not broadcast input array from shape (10) into shape (100)
    |==============================<<
[22:13:38]  Ignored exception:

    |==============================>>
    |  Traceback (most recent call last):
    |    File "/Users/ogi/Developer/pyqtgraph/examples/ImageView.py", line 70, in <module>
    |      QtGui.QApplication.instance().exec_()
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/widgets/GraphicsView.py", line 155, in paintEvent
    |      return QtGui.QGraphicsView.paintEvent(self, ev)
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/debug.py", line 93, in w
    |      printExc('Ignored exception:')
    |    --- exception caught here ---
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/debug.py", line 91, in w
    |      func(*args, **kwds)
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 464, in paint
    |      path = self.getPath()
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 446, in getPath
    |      self.path = self.generatePath(*self.getData())
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 435, in generatePath
    |      path = fn.arrayToQPath(x, y, connect=self.opts['connect'])
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/functions.py", line 1496, in arrayToQPath
    |      arr[1:-1]['y'] = y
    |  ValueError: could not broadcast input array from shape (10) into shape (100)
    |==============================<<
[22:13:38]  Ignored exception:

    |==============================>>
    |  Traceback (most recent call last):
    |    File "/Users/ogi/Developer/pyqtgraph/examples/ImageView.py", line 70, in <module>
    |      QtGui.QApplication.instance().exec_()
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/widgets/GraphicsView.py", line 155, in paintEvent
    |      return QtGui.QGraphicsView.paintEvent(self, ev)
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/debug.py", line 93, in w
    |      printExc('Ignored exception:')
    |    --- exception caught here ---
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/debug.py", line 91, in w
    |      func(*args, **kwds)
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 464, in paint
    |      path = self.getPath()
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 446, in getPath
    |      self.path = self.generatePath(*self.getData())
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/graphicsItems/PlotCurveItem.py", line 435, in generatePath
    |      path = fn.arrayToQPath(x, y, connect=self.opts['connect'])
    |    File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/functions.py", line 1496, in arrayToQPath
    |      arr[1:-1]['y'] = y
    |  ValueError: could not broadcast input array from shape (10) into shape (100)
    |==============================<<
```

### Tested environment(s)

 * PyQtGraph version: 0.11.0 
 * Qt Python binding: PyQt5 5.15.0 Qt 5.15.0
 * Python version: 3.7.7
 * NumPy version: 1.18.5
 * Operating system: macOS 10.15
 * Installation method: pip

### Additional context

None


Discussion:
Introduced with #1203 

There's a potential fix in [the mailing list thread that's referenced in the PR](https://groups.google.com/d/msg/pyqtgraph/SE8KcK2LOv4/Ic07AftBAAAJ
). So far the idea seems to work but I need to do a little more testing. I should have a PR up pretty soon.

Resolving patch:
diff --git a/pyqtgraph/imageview/ImageView.py b/pyqtgraph/imageview/ImageView.py
--- a/pyqtgraph/imageview/ImageView.py
+++ b/pyqtgraph/imageview/ImageView.py
@@ -590,30 +590,42 @@ def roiClicked(self):
         self.ui.roiPlot.setVisible(showRoiPlot)
 
     def roiChanged(self):
+        # Extract image data from ROI
         if self.image is None:
             return
-            
+
         image = self.getProcessedImage()
 
-        # Extract image data from ROI
-        axes = (self.axes['x'], self.axes['y'])
+        # getArrayRegion axes should be (x, y) of data array for col-major,
+        # (y, x) for row-major
+        # can't just transpose input because ROI is axisOrder aware
+        colmaj = self.imageItem.axisOrder == 'col-major'
+        if colmaj:
+            axes = (self.axes['x'], self.axes['y'])
+        else:
+            axes = (self.axes['y'], self.axes['x'])
+
+        data, coords = self.roi.getArrayRegion(
+            image.view(np.ndarray), img=self.imageItem, axes=axes,
+            returnMappedCoords=True)
 
-        data, coords = self.roi.getArrayRegion(image.view(np.ndarray), self.imageItem, returnMappedCoords=True)
         if data is None:
             return
 
         # Convert extracted data into 1D plot data
         if self.axes['t'] is None:
             # Average across y-axis of ROI
-            data = data.mean(axis=axes[1])
-            if axes == (1,0): ## we're in row-major order mode -- there's probably a better way to do this slicing dynamically, but I've not figured it out yet.
-                coords = coords[:,0,:] - coords[:,0,0:1]
-            else: #default to old way
-                coords = coords[:,:,0] - coords[:,0:1,0] 
+            data = data.mean(axis=self.axes['y'])
+
+            # get coordinates along x axis of ROI mapped to range (0, roiwidth)
+            if colmaj:
+                coords = coords[:, :, 0] - coords[:, 0:1, 0]
+            else:
+                coords = coords[:, 0, :] - coords[:, 0, 0:1]
             xvals = (coords**2).sum(axis=0) ** 0.5
         else:
             # Average data within entire ROI for each frame
-            data = data.mean(axis=max(axes)).mean(axis=min(axes))
+            data = data.mean(axis=axes)
             xvals = self.tVals
 
         # Handle multi-channel data


Test patch: