Skip to content

Commit

Permalink
Merge pull request #4305 from janezd/continuous-palettes
Browse files Browse the repository at this point in the history
[ENH] Reorganize continuous palettes
  • Loading branch information
lanzagar authored Feb 7, 2020
2 parents c788de2 + e5b6949 commit f96e566
Show file tree
Hide file tree
Showing 47 changed files with 2,509 additions and 821 deletions.
3 changes: 3 additions & 0 deletions .travis/build_doc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ images="$(git diff --name-only origin/master..HEAD |
echo "Checking if images are indexed:"
while read image; do
[ -f "$image" ] || continue
if [[ "$image" == *"_unindexed"* ]]; then
continue
fi
imtype=$(identify -verbose "$image" | awk '/^ *Type: /{ print $2 }')
echo "$image $imtype"
if ! echo "$imtype" | grep -Eq '(Palette|Grayscale)'; then
Expand Down
68 changes: 17 additions & 51 deletions Orange/data/tests/test_variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,31 +190,6 @@ def test_repr(self):
repr(var),
"DiscreteVariable(name='a', values=['1', '2', '3', '4', '5', '6', '7'])")

@unittest.skipUnless(is_on_path("PyQt4") or is_on_path("PyQt5"), "PyQt is not importable")
def test_colors(self):
var = DiscreteVariable.make("a", values=["F", "M"])
self.assertIsNone(var._colors)
self.assertEqual(var.colors.shape, (2, 3))
self.assertFalse(var.colors.flags.writeable)

var.colors = np.arange(6).reshape((2, 3))
np.testing.assert_almost_equal(var.colors, [[0, 1, 2], [3, 4, 5]])
self.assertFalse(var.colors.flags.writeable)
with self.assertRaises(ValueError):
var.colors[0] = [42, 41, 40]

var = DiscreteVariable.make("x", values=["A", "B"])
var.attributes["colors"] = ['#0a0b0c', '#0d0e0f']
np.testing.assert_almost_equal(var.colors, [[10, 11, 12], [13, 14, 15]])

# Test ncolors adapts to nvalues
var = DiscreteVariable.make('foo', values=['d', 'r'])
self.assertEqual(len(var.colors), 2)
var.add_value('e')
self.assertEqual(len(var.colors), 3)
var.add_value('k')
self.assertEqual(len(var.colors), 4)

def test_no_nonstringvalues(self):
self.assertRaises(TypeError, DiscreteVariable, "foo", values=["a", 42])
a = DiscreteVariable("foo", values=["a", "b", "c"])
Expand Down Expand Up @@ -394,6 +369,23 @@ def varcls_modified(self, name):
var.ordered = True
return var

def test_copy_checks_len_values(self):
var = DiscreteVariable("gender", values=["F", "M"])
self.assertEqual(var.values, ["F", "M"])

self.assertRaises(ValueError, var.copy, values=["F", "M", "N"])
self.assertRaises(ValueError, var.copy, values=["F"])
self.assertRaises(ValueError, var.copy, values=[])

var2 = var.copy()
self.assertEqual(var2.values, ["F", "M"])

var2 = var.copy(values=None)
self.assertEqual(var2.values, ["F", "M"])

var2 = var.copy(values=["W", "M"])
self.assertEqual(var2.values, ["W", "M"])


@variabletest(ContinuousVariable)
class TestContinuousVariable(VariableTest):
Expand Down Expand Up @@ -423,17 +415,6 @@ def test_adjust_decimals(self):
a.val_from_str_add("5.1234")
self.assertEqual(a.str_val(4.65432), "4.6543")

def test_colors(self):
a = ContinuousVariable("a")
self.assertEqual(a.colors, ((0, 0, 255), (255, 255, 0), False))

a = ContinuousVariable("a")
a.attributes["colors"] = ['#010203', '#040506', True]
self.assertEqual(a.colors, ((1, 2, 3), (4, 5, 6), True))

a.colors = ((3, 2, 1), (6, 5, 4), True)
self.assertEqual(a.colors, ((3, 2, 1), (6, 5, 4), True))

def varcls_modified(self, name):
var = super().varcls_modified(name)
var.number_of_decimals = 5
Expand Down Expand Up @@ -621,21 +602,6 @@ def test_make_proxy_cont(self):
self.assertEqual(hash(abc), hash(abc1))
self.assertEqual(hash(abc1), hash(abc2))

def test_proxy_has_separate_colors(self):
abc = ContinuousVariable("abc")
abc1 = abc.make_proxy()
abc2 = abc1.make_proxy()

original_colors = abc.colors
red_to_green = (255, 0, 0), (0, 255, 0), False
blue_to_red = (0, 0, 255), (255, 0, 0), False

abc1.colors = red_to_green
abc2.colors = blue_to_red
self.assertEqual(abc.colors, original_colors)
self.assertEqual(abc1.colors, red_to_green)
self.assertEqual(abc2.colors, blue_to_red)

def test_proxy_has_separate_attributes(self):
image = StringVariable("image")
image1 = image.make_proxy()
Expand Down
48 changes: 7 additions & 41 deletions Orange/data/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import scipy.sparse as sp

from Orange.data import _variable
from Orange.util import Registry, hex_to_color, Reprable,\
OrangeDeprecationWarning
from Orange.util import Registry, Reprable, OrangeDeprecationWarning


__all__ = ["Unknown", "MISSING_VALUES", "make_variable", "is_discrete_values",
"Value", "Variable", "ContinuousVariable", "DiscreteVariable",
Expand Down Expand Up @@ -323,20 +323,11 @@ def __init__(self, name="", compute_value=None, *, sparse=False):
self.source_variable = None
self.sparse = sparse
self.attributes = {}
self._colors = None

@property
def name(self):
return self._name

@property
def colors(self): # unreachable; pragma: no cover
return self._colors

@colors.setter
def colors(self, value):
self._colors = value

def make_proxy(self):
"""
Copy the variable and set the master to `self.master` or to `self`.
Expand Down Expand Up @@ -519,17 +510,6 @@ def format_str(self):
def format_str(self, value):
self._format_str = value

@Variable.colors.getter
def colors(self):
if self._colors is not None:
return self._colors
try:
col1, col2, black = self.attributes["colors"]
return (hex_to_color(col1), hex_to_color(col2), black)
except (KeyError, ValueError):
# User-provided colors were not available or invalid
return ((0, 0, 255), (255, 255, 0), False)

# noinspection PyAttributeOutsideInit
@number_of_decimals.setter
def number_of_decimals(self, x):
Expand Down Expand Up @@ -696,22 +676,6 @@ def mapper(value, col_idx=None):

return mapper

@Variable.colors.getter
def colors(self):
if self._colors is not None:
colors = np.array(self._colors)
elif not self.values:
colors = np.zeros((0, 3)) # to match additional colors in vstacks
else:
from Orange.widgets.utils.colorpalette import ColorPaletteGenerator
default = tuple(ColorPaletteGenerator.palette(self))
colors = self.attributes.get('colors', ())
colors = tuple(hex_to_color(color) for color in colors) \
+ default[len(colors):]
colors = np.array(colors)
colors.flags.writeable = False
return colors

def to_val(self, s):
"""
Convert the given argument to a value of the variable (`float`).
Expand Down Expand Up @@ -744,7 +708,6 @@ def add_value(self, s):
if not isinstance(s, str):
raise TypeError("values of DiscreteVariables must be strings")
self.values.append(s)
self._colors = None

def val_from_str_add(self, s):
"""
Expand Down Expand Up @@ -787,9 +750,12 @@ def __reduce__(self):
self.values, self.ordered), \
__dict__

def copy(self, compute_value=None, *, name=None, **_):
def copy(self, compute_value=None, *, name=None, values=None, **_):
if values is not None and len(values) != len(self.values):
raise ValueError(
"number of values must match the number of original values")
return super().copy(compute_value=compute_value, name=name,
values=self.values, ordered=self.ordered)
values=values or self.values, ordered=self.ordered)


class StringVariable(Variable):
Expand Down
Loading

0 comments on commit f96e566

Please sign in to comment.