Repository: napari/napari

Issue:
Changing contrast_limits on labels layers results in unclear visualization
## 🐛 Bug

I observed weird visualization of labels [deep inside some of my plugin code](https://github.com/clEsperanto/napari_pyclesperanto_assistant/commit/c6db36e1347efb42f83f2035edb95515e704f853) and traced it down to contrast_limits of label layers. The issue is solved on my side, but maybe worth a little change on napari side to prevent others running into this issue. These two lines:

```
layer2 = viewer.add_labels(labels)
layer2.contrast_limits = [0, 100]
```

lead to a misleading lookup table:
![image](https://user-images.githubusercontent.com/12660498/115146278-1717cf00-a056-11eb-9b06-cf3b70423853.png)

If you increase the 100 to 1000, labels become invisible and you can't do anything about it from the user interface.
![image](https://user-images.githubusercontent.com/12660498/115146293-2860db80-a056-11eb-89e2-ca7fc4ecb21f.png)

I conclude changing contrast limits on label layers shouldn't be done in general. Would it be possible to deactivate this function or throw an error message?

## To Reproduce

In a Jupyter notebook, run this code:
```
%gui qt
import numpy as np
from skimage.io import imread
from skimage import filters
from skimage.measure import label
import napari

# blobs example image from ImageJ
image = imread("c:/structure/data/blobs.tif")
threshold = filters.threshold_otsu(image)
thresholded_image = image >= threshold

labels = label(thresholded_image)

# start napari
viewer = napari.Viewer()

# add labels
layer1 = viewer.add_labels(labels)
layer1.visible = False

# add labels with contrast limits
layer2 = viewer.add_labels(labels)
layer2.contrast_limits = [0, 100]
```

## Expected behavior

`label_layer.contrast_limits = ...` throws an error.

## Environment

 - Please copy and paste the information at napari info option in help menubar here:
napari: 0.4.7
Platform: Windows-10-10.0.19041-SP0
Python: 3.8.5 (default, Sep 3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)]
Qt: 5.15.2
PyQt5: 5.15.2
NumPy: 1.19.5
SciPy: 1.6.0
Dask: 2020.12.0
VisPy: 0.6.6

OpenGL:
- GL version: 4.6.0 - Build 27.20.100.8729
- MAX_TEXTURE_SIZE: 16384

Screens:
- screen 1: resolution 1920x1080, scale 2.0

Plugins:
- clEsperanto: 0.7.6
- console: 0.0.2
- svg: 0.1.4

 - Any other relevant information:

## Additional context



Discussion:
> I conclude changing contrast limits on label layers shouldn't be done in general. Would it be possible to deactivate this function or throw an error message?

Yes, this should be done. It also shouldn't be too hard, we just need to overwrite the setter in labels layer https://github.com/napari/napari/blob/master/napari/layers/labels/labels.py, which it is currently just inheriting from the image layer. Contributions from anyone reading this would be welcome here.

Resolving patch:
diff --git a/napari/layers/labels/labels.py b/napari/layers/labels/labels.py
--- a/napari/layers/labels/labels.py
+++ b/napari/layers/labels/labels.py
@@ -669,6 +669,19 @@ def preserve_labels(self, preserve_labels: bool):
         self._preserve_labels = preserve_labels
         self.events.preserve_labels(preserve_labels=preserve_labels)
 
+    @property
+    def contrast_limits(self):
+        return self._contrast_limits
+
+    @contrast_limits.setter
+    def contrast_limits(self, value):
+        # Setting contrast_limits of labels layers leads to wrong visualization of the layer
+        if tuple(value) != (0, 1):
+            raise AttributeError(
+                "Setting contrast_limits on labels layers is not allowed."
+            )
+        self._contrast_limits = (0, 1)
+
     def _set_editable(self, editable=None):
         """Set editable mode based on layer properties."""
         if editable is None:


Test patch: