From 6de8e04fe744e6c60e4302c82bffec7050937b98 Mon Sep 17 00:00:00 2001 From: "P. L. Lim" <2090236+pllim@users.noreply.github.com> Date: Wed, 6 Dec 2023 13:14:07 -0500 Subject: [PATCH 1/2] BUG: Fix Line Profile when there is NaN --- CHANGES.rst | 2 ++ .../line_profile_xy/line_profile_xy.py | 11 ++++--- .../imviz/tests/test_line_profile_xy.py | 29 +++++++++++++++++-- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index ddd374c891..8475f36de3 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -73,6 +73,8 @@ Cubeviz Imviz ^^^^^ +- Line Profile (XY) plugin no longer malfunctions when image contains NaN values. [#2594] + Mosviz ^^^^^^ diff --git a/jdaviz/configs/imviz/plugins/line_profile_xy/line_profile_xy.py b/jdaviz/configs/imviz/plugins/line_profile_xy/line_profile_xy.py index e23760b84e..c29cd7e5df 100644 --- a/jdaviz/configs/imviz/plugins/line_profile_xy/line_profile_xy.py +++ b/jdaviz/configs/imviz/plugins/line_profile_xy/line_profile_xy.py @@ -1,3 +1,4 @@ +import numpy as np from traitlets import Bool, Unicode, observe from jdaviz.configs.imviz.helper import get_top_layer_index @@ -126,11 +127,12 @@ def vue_draw_plot(self, msg={}): self.plot_across_x._update_data('line', x=range(comp.data.shape[0]), y=comp.data[:, x], reset_lims=False) zoomed_data_x = comp.data[y_min:y_max, x] + zoomed_data_x_finite = zoomed_data_x[np.isfinite(zoomed_data_x)] if zoomed_data_x.size > 0: self.plot_across_x.set_limits(x_min=y_min, x_max=y_max, - y_min=zoomed_data_x.min() * 0.95, - y_max=zoomed_data_x.max() * 1.05) + y_min=zoomed_data_x_finite.min() * 0.95, + y_max=zoomed_data_x_finite.max() * 1.05) self.plot_across_x.update_style('line', line_visible=True, markers_visible=False, color='gray', size=10) self.plot_across_x.viewer.axis_x.label = 'Y (pix)' @@ -140,11 +142,12 @@ def vue_draw_plot(self, msg={}): self.plot_across_y._update_data('line', x=range(comp.data.shape[1]), y=comp.data[y, :], reset_lims=False) zoomed_data_y = comp.data[y, x_min:x_max] + zoomed_data_y_finite = zoomed_data_y[np.isfinite(zoomed_data_y)] if zoomed_data_y.size > 0: self.plot_across_y.set_limits(x_min=x_min, x_max=x_max, - y_min=zoomed_data_y.min() * 0.95, - y_max=zoomed_data_y.max() * 1.05) + y_min=zoomed_data_y_finite.min() * 0.95, + y_max=zoomed_data_y_finite.max() * 1.05) self.plot_across_y.update_style('line', line_visible=True, markers_visible=False, color='gray', size=10) self.plot_across_y.viewer.axis_x.label = 'X (pix)' diff --git a/jdaviz/configs/imviz/tests/test_line_profile_xy.py b/jdaviz/configs/imviz/tests/test_line_profile_xy.py index 9229efe7b8..adb1a884c0 100644 --- a/jdaviz/configs/imviz/tests/test_line_profile_xy.py +++ b/jdaviz/configs/imviz/tests/test_line_profile_xy.py @@ -1,7 +1,7 @@ import numpy as np from astropy import units as u from astropy.nddata import NDData -from numpy.testing import assert_allclose +from numpy.testing import assert_allclose, assert_array_equal from jdaviz.configs.imviz.tests.utils import BaseImviz_WCS_NoWCS @@ -9,7 +9,7 @@ class TestLineProfileXY(BaseImviz_WCS_NoWCS): def test_plugin_linked_by_pixel(self): """Go through plugin logic but does not check plot contents.""" - lp_plugin = self.imviz.app.get_tray_item_from_name('imviz-line-profile-xy') + lp_plugin = self.imviz.plugins['Imviz Line Profiles (XY)']._obj lp_plugin.plugin_opened = True assert lp_plugin.viewer.labels == ['imviz-0'] @@ -72,3 +72,28 @@ def test_plugin_linked_by_pixel(self): 'domain': {'x': 5.1, 'y': 5}}) lp_plugin.selected_x = 1.1 lp_plugin.selected_y = 9 + + +def test_line_profile_with_nan(imviz_helper): + arr = np.ones((10, 10)) + arr[5, 5] = np.nan + imviz_helper.load_data(arr) + + lp_plugin = imviz_helper.plugins['Imviz Line Profiles (XY)']._obj + lp_plugin.plugin_opened = True + lp_plugin.selected_x = 5 + lp_plugin.selected_y = 5 + lp_plugin.vue_draw_plot() + assert lp_plugin.plot_available + + # NaN still in data but rendered properly as gap. + # Cannot check the gap stuff in CI but can make sure X-axis is populated properly etc. + for lp_plot in (lp_plugin.plot_across_x, lp_plugin.plot_across_y): + assert lp_plot.layers['line'].state.line_visible + assert not np.all(np.isfinite(lp_plot.layers['line'].layer.data['y'])) + assert_array_equal(lp_plot.layers['line'].layer.data['x'], range(10)) + assert_allclose([lp_plot.layers['line'].state.viewer_state.x_min, + lp_plot.layers['line'].state.viewer_state.x_max, + lp_plot.layers['line'].state.viewer_state.y_min, + lp_plot.layers['line'].state.viewer_state.y_max], + [0, 9, 0.95, 1.05]) From 5bc1855bcc80fb9c7bdce76265e2431d3838104c Mon Sep 17 00:00:00 2001 From: "P. L. Lim" <2090236+pllim@users.noreply.github.com> Date: Wed, 6 Dec 2023 14:07:40 -0500 Subject: [PATCH 2/2] Just use numpy nanmin/nanmax. Co-authored-by: Kyle Conroy --- .../imviz/plugins/line_profile_xy/line_profile_xy.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/jdaviz/configs/imviz/plugins/line_profile_xy/line_profile_xy.py b/jdaviz/configs/imviz/plugins/line_profile_xy/line_profile_xy.py index c29cd7e5df..7497698e3a 100644 --- a/jdaviz/configs/imviz/plugins/line_profile_xy/line_profile_xy.py +++ b/jdaviz/configs/imviz/plugins/line_profile_xy/line_profile_xy.py @@ -127,12 +127,11 @@ def vue_draw_plot(self, msg={}): self.plot_across_x._update_data('line', x=range(comp.data.shape[0]), y=comp.data[:, x], reset_lims=False) zoomed_data_x = comp.data[y_min:y_max, x] - zoomed_data_x_finite = zoomed_data_x[np.isfinite(zoomed_data_x)] if zoomed_data_x.size > 0: self.plot_across_x.set_limits(x_min=y_min, x_max=y_max, - y_min=zoomed_data_x_finite.min() * 0.95, - y_max=zoomed_data_x_finite.max() * 1.05) + y_min=np.nanmin(zoomed_data_x) * 0.95, + y_max=np.nanmax(zoomed_data_x) * 1.05) self.plot_across_x.update_style('line', line_visible=True, markers_visible=False, color='gray', size=10) self.plot_across_x.viewer.axis_x.label = 'Y (pix)' @@ -142,12 +141,11 @@ def vue_draw_plot(self, msg={}): self.plot_across_y._update_data('line', x=range(comp.data.shape[1]), y=comp.data[y, :], reset_lims=False) zoomed_data_y = comp.data[y, x_min:x_max] - zoomed_data_y_finite = zoomed_data_y[np.isfinite(zoomed_data_y)] if zoomed_data_y.size > 0: self.plot_across_y.set_limits(x_min=x_min, x_max=x_max, - y_min=zoomed_data_y_finite.min() * 0.95, - y_max=zoomed_data_y_finite.max() * 1.05) + y_min=np.nanmin(zoomed_data_y) * 0.95, + y_max=np.nanmax(zoomed_data_y) * 1.05) self.plot_across_y.update_style('line', line_visible=True, markers_visible=False, color='gray', size=10) self.plot_across_y.viewer.axis_x.label = 'X (pix)'