From 015a3b0ec790f8f3d8547844c4d838b556ab4bf2 Mon Sep 17 00:00:00 2001 From: Thomas Robitaille Date: Tue, 1 Aug 2017 21:29:31 +0100 Subject: [PATCH 1/3] Sync style of subset group from subset --- glue/core/subset_group.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/glue/core/subset_group.py b/glue/core/subset_group.py index cec46c231..f374476a1 100644 --- a/glue/core/subset_group.py +++ b/glue/core/subset_group.py @@ -19,7 +19,8 @@ from glue.external import six from glue.core.contracts import contract -from glue.core.message import (DataCollectionAddMessage, +from glue.core.message import (SubsetUpdateMessage, + DataCollectionAddMessage, DataCollectionDeleteMessage) from glue.core.visual import VisualAttributes from glue.core.hub import HubListener @@ -147,11 +148,24 @@ def _remove_data(self, data): self.subsets.remove(s) def register_to_hub(self, hub): + hub.subscribe(self, DataCollectionAddMessage, lambda x: self._add_data(x.data)) + hub.subscribe(self, DataCollectionDeleteMessage, lambda x: self._remove_data(x.data)) + def has_subset(msg): + return msg.attribute == 'style' and msg.subset in self.subsets + + hub.subscribe(self, SubsetUpdateMessage, + self._sync_style_from_subset, + filter=has_subset) + + def _sync_style_from_subset(self, msg): + self._style.set(msg.subset.style) + self.broadcast('style') + @property def style(self): return self._style From b1b88cec637ac5767a77a5ca562bc1c1f6f50894 Mon Sep 17 00:00:00 2001 From: Thomas Robitaille Date: Wed, 2 Aug 2017 11:13:10 +0100 Subject: [PATCH 2/3] Added regression test and changelog entry --- CHANGES.md | 3 +++ glue/core/tests/test_subset.py | 43 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 983bee087..eeec300c7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,9 @@ Full changelog v0.11.0 (unreleased) -------------------- +* If a subset's visual properties are changed, change the visual + properties of the parent SubsetGroup. + * Give an error if the user selects a session file when going through the 'Open Data Set' menu. [#1364] diff --git a/glue/core/tests/test_subset.py b/glue/core/tests/test_subset.py index 96713b787..f8aa61e63 100644 --- a/glue/core/tests/test_subset.py +++ b/glue/core/tests/test_subset.py @@ -809,3 +809,46 @@ def test_roi_subset_state(self): data_clone = clone(self.data) assert_equal(data_clone.subsets[0].to_mask(), [0, 1, 0, 0]) + + +def test_changing_subset_style_changes_group(): + + # Test to make sure that if a subset's visual properties are changed, + # the visual properties of all subsets in the same subset group are changed + + d1 = Data(x=[1, 2, 3], label='d1') + d2 = Data(y=[2, 3, 4], label='d2') + d3 = Data(y=[2, 3, 4], label='d3') + + dc = DataCollection([d1, d2, d3]) + + sg = dc.new_subset_group(subset_state=d1.id['x'] > 1, label='A') + + # Changing d1 subset properties changes group and other subsets + + d1.subsets[0].style.color = '#c0b4a1' + assert sg.style.color == '#c0b4a1' + assert d2.subsets[0].style.color == '#c0b4a1' + assert d3.subsets[0].style.color == '#c0b4a1' + + d2.subsets[0].style.alpha = 0.2 + assert sg.style.alpha == 0.2 + assert d1.subsets[0].style.alpha == 0.2 + assert d3.subsets[0].style.alpha == 0.2 + + d3.subsets[0].style.markersize = 16 + assert sg.style.markersize == 16 + assert d1.subsets[0].style.markersize == 16 + assert d2.subsets[0].style.markersize == 16 + + # Changing subset group changes subsets + + sg.style.color = '#abcdef' + assert d1.subsets[0].style.color == '#abcdef' + assert d2.subsets[0].style.color == '#abcdef' + assert d3.subsets[0].style.color == '#abcdef' + + sg.style.linewidth = 12 + assert d1.subsets[0].style.linewidth == 12 + assert d2.subsets[0].style.linewidth == 12 + assert d3.subsets[0].style.linewidth == 12 From 9f4139991bc5f20bdc5ea553d3b2dfc3f762dc6d Mon Sep 17 00:00:00 2001 From: Thomas Robitaille Date: Wed, 2 Aug 2017 12:54:08 +0100 Subject: [PATCH 3/3] Make choice of whether subsets can have individual colors within a group into a preference --- CHANGES.md | 2 +- glue/app/qt/preferences.py | 3 + glue/app/qt/preferences.ui | 109 ++++++++++++++++----------- glue/config.py | 1 + glue/core/subset_group.py | 2 + glue/core/tests/test_subset.py | 43 ----------- glue/core/tests/test_subset_group.py | 66 ++++++++++++++++ 7 files changed, 136 insertions(+), 90 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index eeec300c7..d4072e239 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,7 +5,7 @@ v0.11.0 (unreleased) -------------------- * If a subset's visual properties are changed, change the visual - properties of the parent SubsetGroup. + properties of the parent SubsetGroup. [#1365] * Give an error if the user selects a session file when going through the 'Open Data Set' menu. [#1364] diff --git a/glue/app/qt/preferences.py b/glue/app/qt/preferences.py index c1f03e141..5933fc684 100644 --- a/glue/app/qt/preferences.py +++ b/glue/app/qt/preferences.py @@ -27,6 +27,7 @@ class PreferencesDialog(QtWidgets.QDialog): data_alpha = ValueProperty('ui.slider_alpha', value_range=(0, 1)) data_apply = ButtonProperty('ui.checkbox_apply') show_large_data_warning = ButtonProperty('ui.checkbox_show_large_data_warning') + individual_subset_color = ButtonProperty('ui.checkbox_individual_subset_color') save_to_disk = ButtonProperty('ui.checkbox_save') def __init__(self, application, parent=None): @@ -49,6 +50,7 @@ def __init__(self, application, parent=None): self.data_color = settings.DATA_COLOR self.data_alpha = settings.DATA_ALPHA self.show_large_data_warning = settings.SHOW_LARGE_DATA_WARNING + self.individual_subset_color = settings.INDIVIDUAL_SUBSET_COLOR self._update_theme_from_colors() @@ -94,6 +96,7 @@ def accept(self): settings.DATA_COLOR = self.data_color settings.DATA_ALPHA = self.data_alpha settings.SHOW_LARGE_DATA_WARNING = self.show_large_data_warning + settings.INDIVIDUAL_SUBSET_COLOR = self.individual_subset_color for pane in self.panes: pane.finalize() diff --git a/glue/app/qt/preferences.ui b/glue/app/qt/preferences.ui index fbdc2918c..ec4a27ad0 100644 --- a/glue/app/qt/preferences.ui +++ b/glue/app/qt/preferences.ui @@ -6,8 +6,8 @@ 0 0 - 447 - 357 + 617 + 420 @@ -30,10 +30,13 @@ 15 - - + + - Background color: + Allow subsets within a subset group to have different visual properties + + + true @@ -44,23 +47,6 @@ - - - - - - - true - - - - - - - - - - @@ -68,28 +54,24 @@ - + Qt::Horizontal - - + + - Foreground color: + - - - - - - Default data color: + + true - + @@ -108,38 +90,42 @@ - - + + - Theme for viewers: + Background color: - - - - 100 + + + + Foreground color: - - Qt::Horizontal + + + + + + Default data color: - + - + - + Qt::Horizontal @@ -159,7 +145,7 @@ - + @@ -173,6 +159,37 @@ + + + + Theme for viewers: + + + + + + + 100 + + + Qt::Horizontal + + + + + + + + + + + + + + + + + diff --git a/glue/config.py b/glue/config.py index ded81a63a..811ec32cf 100644 --- a/glue/config.py +++ b/glue/config.py @@ -695,3 +695,4 @@ def _default_search_order(): settings.add('BACKGROUND_COLOR', '#FFFFFF') settings.add('FOREGROUND_COLOR', '#000000') settings.add('SHOW_LARGE_DATA_WARNING', True, validator=bool) +settings.add('INDIVIDUAL_SUBSET_COLOR', False, validator=bool) diff --git a/glue/core/subset_group.py b/glue/core/subset_group.py index f374476a1..d7bf81858 100644 --- a/glue/core/subset_group.py +++ b/glue/core/subset_group.py @@ -163,6 +163,8 @@ def has_subset(msg): filter=has_subset) def _sync_style_from_subset(self, msg): + if settings.INDIVIDUAL_SUBSET_COLOR: + return self._style.set(msg.subset.style) self.broadcast('style') diff --git a/glue/core/tests/test_subset.py b/glue/core/tests/test_subset.py index f8aa61e63..96713b787 100644 --- a/glue/core/tests/test_subset.py +++ b/glue/core/tests/test_subset.py @@ -809,46 +809,3 @@ def test_roi_subset_state(self): data_clone = clone(self.data) assert_equal(data_clone.subsets[0].to_mask(), [0, 1, 0, 0]) - - -def test_changing_subset_style_changes_group(): - - # Test to make sure that if a subset's visual properties are changed, - # the visual properties of all subsets in the same subset group are changed - - d1 = Data(x=[1, 2, 3], label='d1') - d2 = Data(y=[2, 3, 4], label='d2') - d3 = Data(y=[2, 3, 4], label='d3') - - dc = DataCollection([d1, d2, d3]) - - sg = dc.new_subset_group(subset_state=d1.id['x'] > 1, label='A') - - # Changing d1 subset properties changes group and other subsets - - d1.subsets[0].style.color = '#c0b4a1' - assert sg.style.color == '#c0b4a1' - assert d2.subsets[0].style.color == '#c0b4a1' - assert d3.subsets[0].style.color == '#c0b4a1' - - d2.subsets[0].style.alpha = 0.2 - assert sg.style.alpha == 0.2 - assert d1.subsets[0].style.alpha == 0.2 - assert d3.subsets[0].style.alpha == 0.2 - - d3.subsets[0].style.markersize = 16 - assert sg.style.markersize == 16 - assert d1.subsets[0].style.markersize == 16 - assert d2.subsets[0].style.markersize == 16 - - # Changing subset group changes subsets - - sg.style.color = '#abcdef' - assert d1.subsets[0].style.color == '#abcdef' - assert d2.subsets[0].style.color == '#abcdef' - assert d3.subsets[0].style.color == '#abcdef' - - sg.style.linewidth = 12 - assert d1.subsets[0].style.linewidth == 12 - assert d2.subsets[0].style.linewidth == 12 - assert d3.subsets[0].style.linewidth == 12 diff --git a/glue/core/tests/test_subset_group.py b/glue/core/tests/test_subset_group.py index 9897477a3..28b87ae06 100644 --- a/glue/core/tests/test_subset_group.py +++ b/glue/core/tests/test_subset_group.py @@ -3,6 +3,7 @@ import numpy as np from mock import MagicMock, patch +from ...config import settings from .. import DataCollection, Data, SubsetGroup from .. import subset from ..subset import SubsetState @@ -10,6 +11,15 @@ from .test_state import clone +def restore_settings(func): + def wrapper(*args, **kwargs): + settings.reset_defaults() + results = func(*args, **kwargs) + settings.reset_defaults() + return results + return wrapper + + class TestSubsetGroup(object): def setup_method(self, method): @@ -40,12 +50,21 @@ def test_attributes_synced_to_group(self): assert sub.subset_state is sg.subset_state assert sub.label is sg.label + @restore_settings def test_set_style_overrides(self): + + # Test to make sure that if the user has selected to allow individual + # subset colors, the subset color can become out of sync with the + # group color. + + settings.INDIVIDUAL_SUBSET_COLOR = True + self.sg.register(self.dc) sg = self.sg sg.subsets[0].style.color = 'blue' for sub in sg.subsets[1:]: assert sub.style.color != 'blue' + assert sg.subsets[0].style.color == 'blue' def test_new_subset_group_syncs_style(self): @@ -53,7 +72,9 @@ def test_new_subset_group_syncs_style(self): for sub in sg.subsets: assert sub.style == sg.style + @restore_settings def test_set_group_style_clears_override(self): + settings.INDIVIDUAL_SUBSET_COLOR = True sg = self.dc.new_subset_group() style = sg.style.copy() style.parent = sg.subsets[0] @@ -62,6 +83,51 @@ def test_set_group_style_clears_override(self): sg.style.color = 'red' assert sg.subsets[0].style.color == 'red' + def test_changing_subset_style_changes_group(self): + + # Test to make sure that if a subset's visual properties are changed, + # the visual properties of all subsets in the same subset group are changed + + # This is just to make sure the default setting is still False + assert not settings.INDIVIDUAL_SUBSET_COLOR + + d1 = Data(x=[1, 2, 3], label='d1') + d2 = Data(y=[2, 3, 4], label='d2') + d3 = Data(y=[2, 3, 4], label='d3') + + dc = DataCollection([d1, d2, d3]) + + sg = dc.new_subset_group(subset_state=d1.id['x'] > 1, label='A') + + # Changing d1 subset properties changes group and other subsets + + d1.subsets[0].style.color = '#c0b4a1' + assert sg.style.color == '#c0b4a1' + assert d2.subsets[0].style.color == '#c0b4a1' + assert d3.subsets[0].style.color == '#c0b4a1' + + d2.subsets[0].style.alpha = 0.2 + assert sg.style.alpha == 0.2 + assert d1.subsets[0].style.alpha == 0.2 + assert d3.subsets[0].style.alpha == 0.2 + + d3.subsets[0].style.markersize = 16 + assert sg.style.markersize == 16 + assert d1.subsets[0].style.markersize == 16 + assert d2.subsets[0].style.markersize == 16 + + # Changing subset group changes subsets + + sg.style.color = '#abcdef' + assert d1.subsets[0].style.color == '#abcdef' + assert d2.subsets[0].style.color == '#abcdef' + assert d3.subsets[0].style.color == '#abcdef' + + sg.style.linewidth = 12 + assert d1.subsets[0].style.linewidth == 12 + assert d2.subsets[0].style.linewidth == 12 + assert d3.subsets[0].style.linewidth == 12 + def test_new_data_creates_subset(self): sg = self.dc.new_subset_group() d = Data(label='z', z=[10, 20, 30])