diff --git a/CHANGES.md b/CHANGES.md index 495065c76..4b93b02c4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,8 @@ Full changelog v1.4.0 (unreleased) ------------------- +* Add support for specifying visual attributes when creating a subset group. [#2297] + * Modify profile viewer so that when in 'Sum' mode, parts of profiles with no valid values are NaN rather than zero. diff --git a/glue/core/data_collection.py b/glue/core/data_collection.py index 4825fc7a0..753b18e74 100644 --- a/glue/core/data_collection.py +++ b/glue/core/data_collection.py @@ -249,7 +249,7 @@ def register_to_hub(self, hub): lambda msg: self._sync_link_manager(), filter=lambda x: x.sender in self._data) - def new_subset_group(self, label=None, subset_state=None): + def new_subset_group(self, label=None, subset_state=None, **kwargs): """ Create and return a new Subset Group. @@ -265,11 +265,11 @@ def new_subset_group(self, label=None, subset_state=None): :class:`~glue.core.subset_group.SubsetGroup` """ from glue.core.subset_group import SubsetGroup - color = settings.SUBSET_COLORS[self._sg_count % len(settings.SUBSET_COLORS)] + kwargs.setdefault("color", settings.SUBSET_COLORS[self._sg_count % len(settings.SUBSET_COLORS)]) self._sg_count += 1 label = label or 'Subset %i' % self._sg_count - result = SubsetGroup(color=color, label=label, subset_state=subset_state) + result = SubsetGroup(label=label, subset_state=subset_state, **kwargs) self._subset_groups.append(result) result.register(self) return result diff --git a/glue/core/subset_group.py b/glue/core/subset_group.py index 93782857b..b7cf8dff9 100644 --- a/glue/core/subset_group.py +++ b/glue/core/subset_group.py @@ -89,7 +89,7 @@ def __setgluestate__(cls, rec, context): class SubsetGroup(HubListener): - def __init__(self, color=settings.SUBSET_COLORS[0], alpha=0.5, label=None, subset_state=None): + def __init__(self, label=None, subset_state=None, **kwargs): """ Create a new empty SubsetGroup @@ -105,11 +105,13 @@ def __init__(self, color=settings.SUBSET_COLORS[0], alpha=0.5, label=None, subse self.label = label - self.style = VisualAttributes(parent=self) - self.style.markersize *= 2.5 - self.style.linewidth *= 2.5 - self.style.color = color - self.style.alpha = alpha + visual_args = {k: v for k, v in kwargs.items() if k in VisualAttributes.DEFAULT_ATTS} + visual_args.setdefault("color", settings.SUBSET_COLORS[0]) + visual_args.setdefault("alpha", 0.5) + visual_args.setdefault("linewidth", 2.5) + visual_args.setdefault("markersize", 7) + + self.style = VisualAttributes(parent=self, **visual_args) @contract(data='isinstance(DataCollection)') def register(self, data): diff --git a/glue/core/tests/test_subset_group.py b/glue/core/tests/test_subset_group.py index 89c8ce535..3cf497902 100644 --- a/glue/core/tests/test_subset_group.py +++ b/glue/core/tests/test_subset_group.py @@ -174,6 +174,40 @@ def test_deleted_subsets_dont_respawn(self): self.dc.append(d) assert len(d.subsets) == 0 + def test_visual_attributes_default(self): + num_sg = len(self.dc.subset_groups) + sg = self.dc.new_subset_group() + expected_color = settings.SUBSET_COLORS[num_sg % len(settings.SUBSET_COLORS)] + + # VisualAttributes stores color with lowercase letters + # but the values in settings.SUBSET_COLORS use uppercase + expected_color = expected_color.lower() + assert sg.style.color == expected_color + assert sg.style.alpha == 0.5 + assert sg.style.linewidth == 2.5 + assert sg.style.markersize == 7 + assert sg.style.linestyle == 'solid' + assert sg.style.marker == 'o' + assert sg.style.preferred_cmap is None + + def test_visual_attributes(self): + visual_attributes = dict( + color="#ff7f00", + alpha=0.3, + linewidth=4, + markersize=10, + marker='x', + linestyle='dashed', + preferred_cmap='viridis' + ) + sg = self.dc.new_subset_group(**visual_attributes) + for attr, value in visual_attributes.items(): + if attr == 'preferred_cmap': + from matplotlib.cm import get_cmap + assert sg.style.preferred_cmap == get_cmap(visual_attributes[attr]) + else: + assert getattr(sg.style, attr, None) == value + class TestSerialze(TestSubsetGroup): diff --git a/glue/core/visual.py b/glue/core/visual.py index ace6f4ef7..4bef5e1d3 100644 --- a/glue/core/visual.py +++ b/glue/core/visual.py @@ -37,6 +37,9 @@ class VisualAttributes(HasCallbackProperties): The size of the marker. Default is 3. """ + DEFAULT_ATTS = ['color', 'alpha', 'linewidth', 'linestyle', 'marker', + 'markersize', 'preferred_cmap'] + def __init__(self, parent=None, color=None, alpha=None, preferred_cmap=None, linewidth=1, linestyle='solid', marker='o', markersize=3): super(VisualAttributes, self).__init__() @@ -47,8 +50,7 @@ def __init__(self, parent=None, color=None, alpha=None, preferred_cmap=None, lin alpha = alpha or settings.DATA_ALPHA self.parent = parent - self._atts = ['color', 'alpha', 'linewidth', 'linestyle', 'marker', - 'markersize', 'preferred_cmap'] + self._atts = self.DEFAULT_ATTS.copy() self.color = color self.alpha = alpha self.preferred_cmap = preferred_cmap