From 6a88723a12ca64d91a396c19e1e1acd10f83a072 Mon Sep 17 00:00:00 2001 From: Thomas Robitaille Date: Tue, 31 Oct 2023 15:52:14 +0000 Subject: [PATCH 1/3] Added properties to histogram and scatter viewer states to control the percentile to use when determining the min/max in reset_limits, and also added a property to the histogram state to determine whether bins are updated when calling reset_limits. --- glue/viewers/histogram/state.py | 9 +++++++-- glue/viewers/scatter/state.py | 7 +++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/glue/viewers/histogram/state.py b/glue/viewers/histogram/state.py index 730a8cfbd..5e2b38754 100644 --- a/glue/viewers/histogram/state.py +++ b/glue/viewers/histogram/state.py @@ -38,6 +38,10 @@ class HistogramViewerState(MatplotlibDataViewerState): common_n_bin = DDCProperty(True, docstring='The number of bins to use for ' 'all numerical components') + x_limits_percentile = DDCProperty(100, docstring="Percentile to use when automatically determining x limits") + + update_bins_on_reset_limits = DDCProperty(True, docstring="Whether to update the bins to match the view when resetting limits") + def __init__(self, **kwargs): super(HistogramViewerState, self).__init__() @@ -67,9 +71,10 @@ def _reset_x_limits(self, *args): if self.x_att is None: return with delay_callback(self, 'hist_x_min', 'hist_x_max', 'x_min', 'x_max', 'x_log'): - self.x_lim_helper.percentile = 100 + self.x_lim_helper.percentile = self.x_limits_percentile self.x_lim_helper.update_values(force=True) - self.update_bins_to_view() + if self.update_bins_on_reset_limits: + self.update_bins_to_view() def reset_limits(self): self._reset_x_limits() diff --git a/glue/viewers/scatter/state.py b/glue/viewers/scatter/state.py index 528182bd3..db59bc7a5 100644 --- a/glue/viewers/scatter/state.py +++ b/glue/viewers/scatter/state.py @@ -30,6 +30,9 @@ class ScatterViewerState(MatplotlibDataViewerState): plot_mode = DDSCProperty(docstring="Whether to plot the data in cartesian, polar or another projection") angle_unit = DDSCProperty(docstring="Whether to use radians or degrees for any angular coordinates") + x_limits_percentile = DDCProperty(100, docstring="Percentile to use when automatically determining x limits") + y_limits_percentile = DDCProperty(100, docstring="Percentile to use when automatically determining y limits") + def __init__(self, **kwargs): super(ScatterViewerState, self).__init__() @@ -70,13 +73,13 @@ def __init__(self, **kwargs): def _reset_x_limits(self, *args): if self.x_att is None: return - self.x_lim_helper.percentile = 100 + self.x_lim_helper.percentile = self.x_limits_percentile self.x_lim_helper.update_values(force=True) def _reset_y_limits(self, *args): if self.y_att is None: return - self.y_lim_helper.percentile = 100 + self.y_lim_helper.percentile = self.y_limits_percentile self.y_lim_helper.update_values(force=True) def reset_limits(self): From 73ab9dedfcb5497aea45a67dad7a9642fde340b0 Mon Sep 17 00:00:00 2001 From: Thomas Robitaille Date: Tue, 31 Oct 2023 16:14:06 +0000 Subject: [PATCH 2/3] Added unit tests --- glue/viewers/histogram/tests/test_viewer.py | 39 +++++++++++++++++++ glue/viewers/scatter/tests/test_state.py | 43 +++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 glue/viewers/scatter/tests/test_state.py diff --git a/glue/viewers/histogram/tests/test_viewer.py b/glue/viewers/histogram/tests/test_viewer.py index c92c78a88..b3fedb578 100644 --- a/glue/viewers/histogram/tests/test_viewer.py +++ b/glue/viewers/histogram/tests/test_viewer.py @@ -1,4 +1,5 @@ import numpy as np +from numpy.testing import assert_allclose from astropy.utils import NumpyRNGContext @@ -80,3 +81,41 @@ def test_incompatible_datasets(): viewer.state.x_att = data2.id['y'] viewer.state.hist_n_bin = 20 + + +def test_reset_limits(): + + data1 = Data(x=np.arange(1000), label='data') + + app = Application() + app.data_collection.append(data1) + + viewer = app.new_data_viewer(SimpleHistogramViewer) + viewer.add_data(data1) + + viewer.state.reset_limits() + + assert_allclose(viewer.state.x_min, 0) + assert_allclose(viewer.state.x_max, 999) + + viewer.state.x_limits_percentile = 90 + + viewer.state.reset_limits() + + assert_allclose(viewer.state.x_min, 49.95) + assert_allclose(viewer.state.x_max, 949.05) + + assert_allclose(viewer.state.hist_x_min, 49.95) + assert_allclose(viewer.state.hist_x_max, 949.05) + + viewer.state.update_bins_on_reset_limits = False + + viewer.state.x_limits_percentile = 80 + + viewer.state.reset_limits() + + assert_allclose(viewer.state.x_min, 99.9) + assert_allclose(viewer.state.x_max, 899.1) + + assert_allclose(viewer.state.hist_x_min, 49.95) + assert_allclose(viewer.state.hist_x_max, 949.05) diff --git a/glue/viewers/scatter/tests/test_state.py b/glue/viewers/scatter/tests/test_state.py new file mode 100644 index 000000000..da4ddcc9e --- /dev/null +++ b/glue/viewers/scatter/tests/test_state.py @@ -0,0 +1,43 @@ +import numpy as np +from numpy.testing import assert_allclose + +from glue.viewers.common.viewer import Viewer +from glue.viewers.scatter.state import ScatterViewerState +from glue.core.application_base import Application +from glue.core.data import Data + + +class TestScatterViewer(Viewer): + _state_cls = ScatterViewerState + + +def test_reset_limits(): + + data1 = Data(x=np.arange(1000), y=np.arange(1000) + 1000, label='data') + + app = Application() + app.data_collection.append(data1) + + viewer = app.new_data_viewer(TestScatterViewer) + viewer.add_data(data1) + + viewer.state.reset_limits() + + # Note that there is a margin included which is why the limits are not 0 to 999 + + assert_allclose(viewer.state.x_min, -39.96) + assert_allclose(viewer.state.x_max, 1038.96) + + assert_allclose(viewer.state.y_min, 1000 - 39.96) + assert_allclose(viewer.state.y_max, 1000 + 1038.96) + + viewer.state.x_limits_percentile = 90 + viewer.state.y_limits_percentile = 80 + + viewer.state.reset_limits() + + assert_allclose(viewer.state.x_min, 13.986) + assert_allclose(viewer.state.x_max, 985.014) + + assert_allclose(viewer.state.y_min, 1000 + 67.932) + assert_allclose(viewer.state.y_max, 1000 + 931.068) From 422cbe0bd515e952916518274919cab7b92fadc7 Mon Sep 17 00:00:00 2001 From: Derek Homeier Date: Tue, 14 Nov 2023 22:18:03 +0100 Subject: [PATCH 3/3] move test_reset_limits into test_viewer.py --- glue/viewers/scatter/tests/test_state.py | 43 ----------------------- glue/viewers/scatter/tests/test_viewer.py | 35 ++++++++++++++++++ 2 files changed, 35 insertions(+), 43 deletions(-) delete mode 100644 glue/viewers/scatter/tests/test_state.py diff --git a/glue/viewers/scatter/tests/test_state.py b/glue/viewers/scatter/tests/test_state.py deleted file mode 100644 index da4ddcc9e..000000000 --- a/glue/viewers/scatter/tests/test_state.py +++ /dev/null @@ -1,43 +0,0 @@ -import numpy as np -from numpy.testing import assert_allclose - -from glue.viewers.common.viewer import Viewer -from glue.viewers.scatter.state import ScatterViewerState -from glue.core.application_base import Application -from glue.core.data import Data - - -class TestScatterViewer(Viewer): - _state_cls = ScatterViewerState - - -def test_reset_limits(): - - data1 = Data(x=np.arange(1000), y=np.arange(1000) + 1000, label='data') - - app = Application() - app.data_collection.append(data1) - - viewer = app.new_data_viewer(TestScatterViewer) - viewer.add_data(data1) - - viewer.state.reset_limits() - - # Note that there is a margin included which is why the limits are not 0 to 999 - - assert_allclose(viewer.state.x_min, -39.96) - assert_allclose(viewer.state.x_max, 1038.96) - - assert_allclose(viewer.state.y_min, 1000 - 39.96) - assert_allclose(viewer.state.y_max, 1000 + 1038.96) - - viewer.state.x_limits_percentile = 90 - viewer.state.y_limits_percentile = 80 - - viewer.state.reset_limits() - - assert_allclose(viewer.state.x_min, 13.986) - assert_allclose(viewer.state.x_max, 985.014) - - assert_allclose(viewer.state.y_min, 1000 + 67.932) - assert_allclose(viewer.state.y_max, 1000 + 931.068) diff --git a/glue/viewers/scatter/tests/test_viewer.py b/glue/viewers/scatter/tests/test_viewer.py index 9fe1a05e9..98de3806d 100644 --- a/glue/viewers/scatter/tests/test_viewer.py +++ b/glue/viewers/scatter/tests/test_viewer.py @@ -1,3 +1,6 @@ +import numpy as np +from numpy.testing import assert_allclose + from glue.tests.visual.helpers import visual_test from glue.viewers.scatter.viewer import SimpleScatterViewer @@ -24,3 +27,35 @@ def test_simple_viewer(): app.data_collection.new_subset_group(label='subset1', subset_state=data1.id['x'] > 2) return viewer.figure + + +def test_reset_limits(): + + data1 = Data(x=np.arange(1000), y=np.arange(1000) + 1000, label='data') + + app = Application() + app.data_collection.append(data1) + + viewer = app.new_data_viewer(SimpleScatterViewer) + viewer.add_data(data1) + + viewer.state.reset_limits() + + # Note that there is a margin included which is why the limits are not 0 to 999 + + assert_allclose(viewer.state.x_min, -39.96) + assert_allclose(viewer.state.x_max, 1038.96) + + assert_allclose(viewer.state.y_min, 1000 - 39.96) + assert_allclose(viewer.state.y_max, 1000 + 1038.96) + + viewer.state.x_limits_percentile = 90 + viewer.state.y_limits_percentile = 80 + + viewer.state.reset_limits() + + assert_allclose(viewer.state.x_min, 13.986) + assert_allclose(viewer.state.x_max, 985.014) + + assert_allclose(viewer.state.y_min, 1000 + 67.932) + assert_allclose(viewer.state.y_max, 1000 + 931.068)