Skip to content

Commit

Permalink
Improve multiple colors behavior in relevant layers (napari#782)
Browse files Browse the repository at this point in the history
* Allow a single point to be added as 1D

* Added possible color configs to test

* Basic color tests for add_points

* Basic mechanism of color handling

* Mock data for tests

* Added color transformation and appropriate tests

* Moved transform function and its tests

* Improved tests

* Refactored Points layer object

* Minor test addition

* Test modifications

* Points layer uses ColorArray

* Point layer is now integrated with ColorArray colors, tests of it pass

* Fixed hex conversion, all tests pass

* Added test, fixed small bug with tiling

* edge_ and face_color save last used color

* added transparent color option

* Moved color-handling files to their own folder

* Renamed utils

* Removed old util module

* Fixed point selection bug

* Fixed faulty import

* Fixed numpy 1.17 deprecation becoming hard error in 1.18

* Fix numpy deprecation again

* Resolve conflict

* Fixed comments in PR and logic errors

* Refactoring according to comments, test should pass

* Fixed default face_color value

* Working on standardization color, half-way through

* More extensive work on standardize_color

* All tests besides the RGBA one pass

* Color tests pass

* Removing .rgba from the wild

* Removed .rgba isntances from relevant parts

* Got rid of ColorArray in layers

* Fixed tests to pass without ColorArray

* Last fixes for tests

* Moved tiling and transformation methods to their own utils module

* Various fixes from review

* Better param names

* More basic color manipulation fixes

* Applying suggestions

* Reverting old changes

* Remove support for list or tuple of arrays

* Transparent color is now working

* Better explain the logic behind combobox

* Fixed merge conflicts

* Formatting and other minor changes

* Added explicit copy flag, tests do not warn anymore

* Formatting
  • Loading branch information
HagaiHargil authored and kevinyamauchi committed Jan 16, 2020
1 parent b45a26d commit 8554776
Show file tree
Hide file tree
Showing 17 changed files with 1,027 additions and 154 deletions.
42 changes: 31 additions & 11 deletions napari/_qt/layers/qt_points_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
QFrame,
QHBoxLayout,
)
from vispy.color import Color

from .qt_base_layer import QtLayerControls
from ...layers.points._constants import Mode, Symbol
from ..qt_mode_buttons import QtModeRadioButton, QtModePushButton
Expand Down Expand Up @@ -170,22 +170,42 @@ def _on_size_change(self, event=None):
self.sizeSlider.setValue(int(value))

def _on_edge_color_change(self, event=None):
"""Change element's edge color based on user-provided value.
The new color (read from layer.current_edge_color) is a string -
either the color's name or its hex representation. This color has
already been verified by "transform_color". This value has to be
looked up in the color list of the layer and displayed in the
combobox. If it's not in the combobox the method will add it and
then display it, for future use.
"""
color = self.layer.current_edge_color
with self.layer.events.edge_color.blocker():
index = self.edgeComboBox.findText(
self.layer.current_edge_color, Qt.MatchFixedString
)
index = self.edgeComboBox.findText(color, Qt.MatchFixedString)
if index == -1:
self.edgeComboBox.addItem(color)
index = self.edgeComboBox.findText(color, Qt.MatchFixedString)
self.edgeComboBox.setCurrentIndex(index)
color = Color(self.layer.current_edge_color).hex
self.edgeColorSwatch.setStyleSheet("background-color: " + color)
self.edgeColorSwatch.setStyleSheet(f"background-color: {color}")

def _on_face_color_change(self, event=None):
"""Change element's face color based user-provided value.
The new color (read from layer.current_face_color) is a string -
either the color's name or its hex representation. This color has
already been verified by "transform_color". This value has to be
looked up in the color list of the layer and displayed in the
combobox. If it's not in the combobox the method will add it and
then display it, for future use.
"""
color = self.layer.current_face_color
with self.layer.events.face_color.blocker():
index = self.faceComboBox.findText(
self.layer.current_face_color, Qt.MatchFixedString
)
index = self.faceComboBox.findText(color, Qt.MatchFixedString)
if index == -1:
self.faceComboBox.addItem(color)
index = self.faceComboBox.findText(color, Qt.MatchFixedString)
self.faceComboBox.setCurrentIndex(index)
color = Color(self.layer.current_face_color).hex
self.faceColorSwatch.setStyleSheet("background-color: " + color)
self.faceColorSwatch.setStyleSheet(f"background-color: {color}")

def _on_editable_change(self, event=None):
self.select_button.setEnabled(self.layer.editable)
Expand Down
15 changes: 15 additions & 0 deletions napari/_qt/tests/test_qt_layerlist.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import numpy as np
from vispy.color import get_color_dict

from napari.components import LayerList
from napari.layers import Image
from napari._qt.qt_layerlist import QtLayerList, QtDivider
from napari.utils.colormaps.standardize_color import hex_to_name


def check_layout_layers(layout, layers):
Expand Down Expand Up @@ -206,3 +208,16 @@ def test_reordering_layers(qtbot):
assert view.vbox_layout.count() == 2 * (len(layers) + 1)
assert check_layout_layers(view.vbox_layout, layers)
assert check_layout_dividers(view.vbox_layout, len(layers))


def test_hex_to_name_is_updated():
fail_msg = (
"If this test fails then vispy have probably updated their color dictionary, located "
"in vispy.color.get_color_dict. This not necessarily a bad thing, but make sure that "
"nothing terrible has happened due to this change."
)
new_hex_to_name = {
f"{v.lower()}ff": k for k, v in get_color_dict().items()
}
new_hex_to_name["#00000000"] = 'transparent'
assert new_hex_to_name == hex_to_name, fail_msg
20 changes: 8 additions & 12 deletions napari/_vispy/vispy_points_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from vispy.scene.visuals import Line, Compound
from .markers import Markers
from vispy.visuals.transforms import ChainTransform

from .vispy_base_layer import VispyBaseLayer


Expand Down Expand Up @@ -51,15 +52,11 @@ def _on_data_change(self, event=None):
self._on_highlight_change()

if len(self.layer._data_view) > 0:
edge_color = [
self.layer.edge_color[i] for i in self.layer._indices_view
]
face_color = [
self.layer.face_color[i] for i in self.layer._indices_view
]
edge_color = self.layer.edge_color[self.layer._indices_view]
face_color = self.layer.face_color[self.layer._indices_view]
else:
edge_color = 'white'
face_color = 'white'
edge_color = np.array([[0.0, 0.0, 0.0, 1.0]], dtype=np.float32)
face_color = np.array([[1.0, 1.0, 1.0, 1.0]], dtype=np.float32)

# Set vispy data, noting that the order of the points needs to be
# reversed to make the most recently added point appear on top
Expand Down Expand Up @@ -97,14 +94,13 @@ def _on_highlight_change(self, event=None):
if data.ndim == 1:
data = np.expand_dims(data, axis=0)
size = self.layer._size_view[self.layer._highlight_index]
face_color = [
self.layer.face_color[i]
for i in self.layer._indices_view[self.layer._highlight_index]
face_color = self.layer.face_color[
self.layer._indices_view[self.layer._highlight_index]
]
else:
data = np.zeros((1, self.layer.dims.ndisplay))
size = 0
face_color = 'white'
face_color = np.array([[1.0, 1.0, 1.0, 1.0]], dtype=np.float32)

self.node._subvisuals[1].set_data(
data[:, ::-1] + 0.5,
Expand Down
3 changes: 2 additions & 1 deletion napari/components/tests/test_multichannel.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import numpy as np
import dask.array as da
from napari.components import ViewerModel
from napari.utils import colormaps
from napari.utils.colormaps import colormaps


base_colormaps = colormaps.CYMRGB
two_colormaps = colormaps.MAGENTA_GREEN
Expand Down
11 changes: 6 additions & 5 deletions napari/components/viewer_model.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import numpy as np
from math import inf
import itertools
from xml.etree.ElementTree import Element, tostring

import numpy as np

from .dims import Dims
from .layerlist import LayerList
from .. import layers
Expand Down Expand Up @@ -616,10 +617,10 @@ def add_points(
broadcastable to the same shape as the data.
edge_width : float
Width of the symbol edge in pixels.
edge_color : str
Color of the point marker border.
face_color : str
Color of the point marker body.
edge_color : str, array-like
Color of the point marker border. Numeric color values should be RGB(A).
face_color : str, array-like
Color of the point marker body. Numeric color values should be RGB(A).
n_dimensional : bool
If True, renders points not just in central plane but also in all
n-dimensions according to specified point marker size.
Expand Down
6 changes: 3 additions & 3 deletions napari/layers/labels/tests/test_label_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

def test_interpolate_coordinates():
# test when number of interpolated points > 1
old_coord = np.asarray([0, 1])
new_coord = np.asarray([0, 10])
old_coord = np.array([0, 1])
new_coord = np.array([0, 10])
coords = interpolate_coordinates(old_coord, new_coord, brush_size=3)
expected_coords = np.asarray(
expected_coords = np.array(
[
[0, 1.75],
[0, 2.5],
Expand Down
Loading

0 comments on commit 8554776

Please sign in to comment.