Repository: pyqtgraph/pyqtgraph

Issue:
ImageView(levelMode='rgba') throws exception
<!-- In the following, please describe your issue in detail! -->
<!-- If some of the sections do not apply, just remove them. -->

### Short description
<!-- This should summarize the issue. -->
Instantiating ImageView widget as ImageView(levelMode='rgba') causes an exception in HistogramLUTItem.
Providing an ImageItem upon instantation doesn't help.

Changing the levelMode to rgba after instantiation does work as shown in the "workaround" codepath.

### Code to reproduce
<!-- Please provide a minimal working example that reproduces the issue in the code block below.
     Ideally, this should be a full example someone else could run without additional setup. -->
```python
import pyqtgraph as pg
import numpy as np

data = np.random.randint(256, size=(256,256,3))

app = pg.mkQApp()

imgitem = pg.ImageItem(data)
if 1:
    # fails
    imv = pg.ImageView(imageItem=imgitem, levelMode='rgba')
else:
    # workaround
    imv = pg.ImageView(imageItem=imgitem)
    imv.getHistogramWidget().item.setLevelMode('rgba')
imv.show()

app.exec_()
```

### Expected behavior
<!-- What should happen? -->
Program starts with no exception thrown

### Real behavior
<!-- What happens? -->

```
Traceback (most recent call last):
  File "d:\github\pyqtgraph\pyqtgraph\imageview\ImageView.py", line 130, in __init__
    self.ui.histogram.setLevelMode(levelMode)
  File "d:\github\pyqtgraph\pyqtgraph\graphicsItems\HistogramLUTItem.py", line 309, in setLevelMode
    self._showRegions()
  File "d:\github\pyqtgraph\pyqtgraph\graphicsItems\HistogramLUTItem.py", line 337, in _showRegions
    xdif = 1.0 / nch
UnboundLocalError: local variable 'nch' referenced before assignment
```


### Tested environment(s)

 * PyQtGraph version: master <!-- output of pyqtgraph.__version__ -->
 * Qt Python binding: PySide6 6.0.4 Qt 6.0.4<!-- output of pyqtgraph.Qt.VERSION_INFO -->
 * Python version: 3.8.9
 * NumPy version: 1.20.2 <!-- output of numpy.__version__ -->
 * Operating system: Windows 10
 * Installation method: pip install -e . <!-- e.g. pip, conda, system packages, ... -->

### Additional context



Discussion:
Good catch. There's a quick fix which would be to move the `HistogramLUTItem.setLevelMode` call to after the `HistogramLUTItem.setImageItem` call (effectively the same as your workaround):

https://github.com/pyqtgraph/pyqtgraph/blob/96e83b7d437db3254121569463f63b78b4cd7101/pyqtgraph/imageview/ImageView.py#L130

https://github.com/pyqtgraph/pyqtgraph/blob/96e83b7d437db3254121569463f63b78b4cd7101/pyqtgraph/imageview/ImageView.py#L149

However, `HistogramLUTItem` needs a review (and tests) to make sure its methods are robust to not yet having an associated `ImageItem`.


Resolving patch:
diff --git a/pyqtgraph/graphicsItems/HistogramLUTItem.py b/pyqtgraph/graphicsItems/HistogramLUTItem.py
--- a/pyqtgraph/graphicsItems/HistogramLUTItem.py
+++ b/pyqtgraph/graphicsItems/HistogramLUTItem.py
@@ -443,7 +443,7 @@ def _showRegions(self):
             self.regions[i].setVisible(False)
 
         if self.levelMode == 'rgba':
-            imax = 4
+            nch = 4
             if self.imageItem() is not None:
                 # Only show rgb channels if connected image lacks alpha.
                 nch = self.imageItem().channels()
diff --git a/pyqtgraph/imageview/ImageView.py b/pyqtgraph/imageview/ImageView.py
--- a/pyqtgraph/imageview/ImageView.py
+++ b/pyqtgraph/imageview/ImageView.py
@@ -127,7 +127,6 @@ def __init__(self, parent=None, name="ImageView", view=None, imageItem=None,
         self.ui = ui_template.Ui_Form()
         self.ui.setupUi(self)
         self.scene = self.ui.graphicsView.scene()
-        self.ui.histogram.setLevelMode(levelMode)
         
         self.ignorePlaying = False
         
@@ -139,15 +138,6 @@ def __init__(self, parent=None, name="ImageView", view=None, imageItem=None,
         self.view.setAspectLocked(True)
         self.view.invertY()
         
-        if imageItem is None:
-            self.imageItem = ImageItem()
-        else:
-            self.imageItem = imageItem
-        self.view.addItem(self.imageItem)
-        self.currentIndex = 0
-        
-        self.ui.histogram.setImageItem(self.imageItem)
-        
         self.menu = None
         
         self.ui.normGroup.hide()
@@ -171,6 +161,18 @@ def __init__(self, parent=None, name="ImageView", view=None, imageItem=None,
         self.timeLine.setZValue(1)
         self.ui.roiPlot.addItem(self.timeLine)
         self.ui.splitter.setSizes([self.height()-35, 35])
+
+        # init imageItem and histogram
+        if imageItem is None:
+            self.imageItem = ImageItem()
+        else:
+            self.imageItem = imageItem
+            self.setImage(imageItem.image, autoRange=False, autoLevels=False, transform=imageItem.transform())
+        self.view.addItem(self.imageItem)
+        self.currentIndex = 0
+        
+        self.ui.histogram.setImageItem(self.imageItem)
+        self.ui.histogram.setLevelMode(levelMode)
         
         # make splitter an unchangeable small grey line:
         s = self.ui.splitter


Test patch:
diff --git a/tests/imageview/test_imageview.py b/tests/imageview/test_imageview.py
--- a/tests/imageview/test_imageview.py
+++ b/tests/imageview/test_imageview.py
@@ -10,3 +10,9 @@ def test_nan_image():
     v.imageItem.getHistogram()
     app.processEvents()
     v.window().close()
+
+def test_init_with_mode_and_imageitem():
+    data = np.random.randint(256, size=(256, 256, 3))
+    imgitem = pg.ImageItem(data)
+    pg.ImageView(imageItem=imgitem, levelMode="rgba")
+    assert(pg.image is not None)