diff --git a/glue/viewers/image/qt/tests/test_data_viewer.py b/glue/viewers/image/qt/tests/test_data_viewer.py
index c607ddf40..a681efbd2 100644
--- a/glue/viewers/image/qt/tests/test_data_viewer.py
+++ b/glue/viewers/image/qt/tests/test_data_viewer.py
@@ -5,6 +5,7 @@
from collections import Counter
import pytest
+from unittest.mock import MagicMock
from astropy.wcs import WCS
@@ -740,6 +741,41 @@ def test_legend(self):
assert to_hex(handles[1].get_facecolor()) == viewer_state.layers[1].color
+ def test_recalculate_wcs(self):
+
+ # Test to make sure we skip recalculating WCS when appropriate
+
+ mock = MagicMock(wraps=self.viewer.axes.reset_wcs)
+ self.viewer.axes.reset_wcs = mock
+
+ coords = self.hypercube_wcs.coords
+ coords.wcs.crpix = [1.2, 2, 2.25, 1.9]
+ coords.wcs.cdelt = np.array([-6.7, 6.7, 5.1, -4.6])
+ coords.wcs.crval = [0, -90, 10, 40]
+ coords.wcs.ctype = ["RA---SFL", "DEC--SFL", "VOPT", "ZOPT"]
+ coords.wcs.specsys = "LSRK"
+ self.viewer.add_data(self.hypercube_wcs)
+ self.viewer.state.x_att = self.hypercube_wcs.pixel_component_ids[0]
+ self.viewer.state.y_att = self.hypercube_wcs.pixel_component_ids[3]
+ self.viewer.state.slices = [0, 0, 0, 0]
+
+ mock.reset_mock()
+ self.viewer.state.slices = [0, 2, 3, 0]
+ mock.assert_called()
+
+ mock.reset_mock()
+ self.viewer.state.show_axes = False
+ self.viewer.state.slices = [0, 1, 0, 0]
+ mock.assert_not_called()
+
+ mock.reset_mock()
+ self.viewer.state.x_att = self.hypercube_wcs.pixel_component_ids[1]
+ mock.assert_called()
+
+ mock.reset_mock()
+ self.viewer.state.slices = [1, 1, 0, 0]
+ mock.assert_not_called()
+
class TestSessions(object):
diff --git a/glue/viewers/image/qt/tests/test_python_export.py b/glue/viewers/image/qt/tests/test_python_export.py
index 3ee339619..01ed82a7c 100644
--- a/glue/viewers/image/qt/tests/test_python_export.py
+++ b/glue/viewers/image/qt/tests/test_python_export.py
@@ -7,6 +7,8 @@
from glue.viewers.image.qt import ImageViewer
from glue.viewers.matplotlib.qt.tests.test_python_export import BaseTestExportPython
+from astropy.wcs import WCS
+
class TestExportPython(BaseTestExportPython):
@@ -85,3 +87,16 @@ def test_subset_transposed(self, tmpdir):
self.viewer.state.y_att = self.data.pixel_component_ids[1]
self.data_collection.new_subset_group('mysubset', self.data.id['cube'] > 0.5)
self.assert_same(tmpdir)
+
+ def test_hide_axes(self, tmpdir):
+ self.viewer.state.aspect = 'auto'
+ self.viewer.state.x_min = -5
+ self.viewer.state.y_min = -3
+ self.viewer.state.x_max = 30
+ self.viewer.state.y_max = 55
+ super().test_hide_axes(tmpdir)
+
+ def test_wcs_image(self, tmpdir):
+ coords = WCS(naxis=3)
+ wcs_data = Data(self.data.data)
+ self.assert_same(tmpdir)
diff --git a/glue/viewers/image/viewer.py b/glue/viewers/image/viewer.py
index a0c24dd5d..29837952f 100644
--- a/glue/viewers/image/viewer.py
+++ b/glue/viewers/image/viewer.py
@@ -68,6 +68,13 @@ def update_y_ticklabel(self, *event):
self.axes.coords[axis].set_ticklabel(size=self.state.y_ticklabel_size)
self.redraw()
+ def update_axes_visibility(self, *event):
+ if self.state.show_axes:
+ self._set_wcs()
+ else:
+ self._changing_slice_requires_wcs_update = False
+ super(MatplotlibImageMixin, self).update_axes_visibility(event)
+
def _update_axes(self, *args):
if self.state.x_att_world is not None:
@@ -132,7 +139,7 @@ def _set_wcs(self, event=None, relim=True):
y_dep.remove(ix)
if iy in y_dep:
y_dep.remove(iy)
- self._changing_slice_requires_wcs_update = bool(x_dep or y_dep)
+ self._changing_slice_requires_wcs_update = bool(x_dep or y_dep) and self.state.show_axes
self._wcs_set = True
@@ -219,7 +226,7 @@ def _script_header(self):
ref_coords = self.state.reference_data.coords
if hasattr(ref_coords, 'wcs'):
- script += "ax.reset_wcs(slices={0}, wcs=ref_data.coords.wcs)\n".format(self.state.wcsaxes_slice)
+ script += "ax.reset_wcs(slices={0}, wcs=ref_data.coords)\n".format(self.state.wcsaxes_slice)
elif hasattr(ref_coords, 'wcsaxes_dict'):
raise NotImplementedError()
else:
diff --git a/glue/viewers/matplotlib/mpl_axes.py b/glue/viewers/matplotlib/mpl_axes.py
index 61ab8e313..efc0e13db 100644
--- a/glue/viewers/matplotlib/mpl_axes.py
+++ b/glue/viewers/matplotlib/mpl_axes.py
@@ -5,6 +5,8 @@
__all__ = ['update_appearance_from_settings', 'init_mpl']
+DEFAULT_MARGIN = [1, 0.25, 0.50, 0.25]
+
def set_background_color(axes, color):
axes.figure.set_facecolor(color)
@@ -59,7 +61,7 @@ def init_mpl(figure=None, axes=None, wcs=False, axes_factory=None):
else:
_axes = axes_factory(_figure)
- freeze_margins(_axes, margins=[1, 0.25, 0.50, 0.25])
+ freeze_margins(_axes, margins=DEFAULT_MARGIN)
update_appearance_from_settings(_axes)
diff --git a/glue/viewers/matplotlib/qt/axes_editor.ui b/glue/viewers/matplotlib/qt/axes_editor.ui
index eee77d0dd..91986aaed 100644
--- a/glue/viewers/matplotlib/qt/axes_editor.ui
+++ b/glue/viewers/matplotlib/qt/axes_editor.ui
@@ -6,8 +6,8 @@
0
0
- 272
- 286
+ 259
+ 237
@@ -29,6 +29,59 @@
5
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Apply to all plots
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ axis label weight
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ -
+
+
-
@@ -39,24 +92,56 @@
- -
-
+
-
+
+
+
+ 50
+ false
+
+
+
+ y
+
+
+ Qt::AlignCenter
+
+
- -
-
-
-
- 70
- 0
-
+
-
+
+
+ -
+
+
+
+ 50
+ false
+
+
+
+ x
+
+
+ Qt::AlignCenter
- -
-
+
-
+
+
+ axis label size
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
- -
-
+
-
+
+
+ -
+
-
@@ -68,7 +153,7 @@
- -
+
-
tick label size
@@ -78,17 +163,20 @@
- -
-
-
- -
-
-
- Qt::Horizontal
+
-
+
+
+
+ 70
+ 0
+
- -
+
-
+
+
+ -
@@ -98,46 +186,30 @@
- -
-
-
- axis label size
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- axis label weight
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
-
+
+
+ Qt::Horizontal
- -
-
-
-
- 50
- false
-
-
-
- x
+
-
+
+
+ Qt::Vertical
-
- Qt::AlignCenter
+
+
+ 20
+ 0
+
-
+
- -
-
+
-
+
-
-
+
Qt::Horizontal
@@ -150,14 +222,17 @@
-
-
+
- Apply to all plots
+ Show axes
+
+
+ true
-
-
+
Qt::Horizontal
@@ -171,41 +246,6 @@
- -
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 0
-
-
-
-
- -
-
-
-
- 50
- false
-
-
-
- y
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
diff --git a/glue/viewers/matplotlib/qt/tests/test_data_viewer.py b/glue/viewers/matplotlib/qt/tests/test_data_viewer.py
index 87e9af8e0..847be6e74 100644
--- a/glue/viewers/matplotlib/qt/tests/test_data_viewer.py
+++ b/glue/viewers/matplotlib/qt/tests/test_data_viewer.py
@@ -16,6 +16,7 @@
from glue.core.roi import XRangeROI
from glue.utils.qt import process_events
from glue.tests.helpers import requires_matplotlib_ge_22
+from glue.viewers.matplotlib.state import MatplotlibDataViewerState
class MatplotlibDrawCounter(object):
@@ -667,3 +668,31 @@ def test_legend_numerical_data_changed(self):
data.add_component(self.data[cid], cid.label)
self.data.update_values_from_data(data)
assert self.draw_count == 2
+
+ def test_hide_axes(self):
+ assert self.viewer.axes.axison
+
+ self.viewer.state.show_axes = False
+ assert not self.viewer.axes.axison
+
+ self.viewer.state.show_axes = True
+ assert self.viewer.axes.axison
+
+ def test_update_settings_from(self):
+ copy_from_state = MatplotlibDataViewerState()
+ copy_from_state.x_axislabel_size = 1
+ copy_from_state.y_axislabel_size = 2
+ copy_from_state.x_axislabel_weight = 'heavy'
+ copy_from_state.y_axislabel_weight = 'black'
+ copy_from_state.x_ticklabel_size = 5
+ copy_from_state.y_ticklabel_size = 6
+ copy_from_state.show_axes = False
+ state = self.viewer.state
+ state.update_axes_settings_from(copy_from_state)
+ assert state.x_axislabel_size == 1
+ assert state.y_axislabel_size == 2
+ assert state.x_axislabel_weight == 'heavy'
+ assert state.y_axislabel_weight == 'black'
+ assert state.x_ticklabel_size == 5
+ assert state.y_ticklabel_size == 6
+ assert not state.show_axes
diff --git a/glue/viewers/matplotlib/qt/tests/test_python_export.py b/glue/viewers/matplotlib/qt/tests/test_python_export.py
index 40c0760df..d2c00f9be 100644
--- a/glue/viewers/matplotlib/qt/tests/test_python_export.py
+++ b/glue/viewers/matplotlib/qt/tests/test_python_export.py
@@ -50,3 +50,7 @@ def assert_same(self, tmpdir, tol=0.1):
print(b64encode(f.read()).decode())
pytest.fail(msg, pytrace=False)
+
+ def test_hide_axes(self, tmpdir):
+ self.viewer.state.show_axes = False
+ self.assert_same(tmpdir)
diff --git a/glue/viewers/matplotlib/state.py b/glue/viewers/matplotlib/state.py
index 7905e5410..267256b2d 100644
--- a/glue/viewers/matplotlib/state.py
+++ b/glue/viewers/matplotlib/state.py
@@ -91,8 +91,8 @@ def mpl_location(self):
return self.location
def update_axes_settings_from(self, state):
- self.visible = state.show_legend
- self.loc_and_drag = state.loc_and_drag
+ self.visible = state.visible
+ self.location = state.location
self.alpha = state.alpha
self.title = state.title
self.fontsize = state.fontsize
@@ -244,6 +244,7 @@ def update_axes_settings_from(self, state):
self.y_ticklabel_size = state.y_ticklabel_size
# legend
self.legend.update_axes_settings_from(state.legend)
+ self.show_axes = state.show_axes
@defer_draw
def _notify_global(self, *args, **kwargs):
diff --git a/glue/viewers/matplotlib/viewer.py b/glue/viewers/matplotlib/viewer.py
index b068ec30d..f2e62e51c 100644
--- a/glue/viewers/matplotlib/viewer.py
+++ b/glue/viewers/matplotlib/viewer.py
@@ -5,9 +5,10 @@
from matplotlib.patches import Rectangle
from matplotlib.artist import setp as msetp
-from glue.viewers.matplotlib.mpl_axes import update_appearance_from_settings
+from glue.viewers.matplotlib.mpl_axes import update_appearance_from_settings, DEFAULT_MARGIN
from echo import delay_callback
from glue.utils import mpl_to_datetime64
+from glue.utils.matplotlib import freeze_margins
__all__ = ['MatplotlibViewerMixin']
@@ -31,6 +32,10 @@
ax.set_xscale('{x_log_str}')
ax.set_yscale('{y_log_str}')
+# Enable or disable the drawing of axes and remove margin if hiding axes
+ax.set_axis_{show_axes}()
+{margin}
+
# Set axis label properties
ax.set_xlabel('{x_axislabel}', weight='{x_axislabel_weight}', size={x_axislabel_size})
ax.set_ylabel('{y_axislabel}', weight='{y_axislabel_weight}', size={y_axislabel_size})
@@ -117,6 +122,7 @@ def setup_callbacks(self):
self.state.add_callback('x_ticklabel_size', self.update_x_ticklabel)
self.state.add_callback('y_ticklabel_size', self.update_y_ticklabel)
+ self.state.add_callback('show_axes', self.update_axes_visibility)
self.state.legend.add_callback('visible', self.draw_legend)
self.state.legend.add_callback('location', self.draw_legend)
@@ -207,6 +213,16 @@ def draw_legend(self, *args):
legend.remove()
self.redraw()
+ def update_axes_visibility(self, *event):
+ if self.state.show_axes:
+ self.axes.set_axis_on()
+ freeze_margins(self.axes, margins=DEFAULT_MARGIN)
+ else:
+ self.axes.set_axis_off()
+ freeze_margins(self.axes, margins=[0., 0., 0., 0.])
+ # Have to force a resize event to update margins
+ self.axes.figure.canvas.resize_event()
+
def redraw(self):
self.figure.canvas.draw_idle()
@@ -312,6 +328,8 @@ def _script_footer(self):
state_dict = self.state.as_dict()
state_dict['x_log_str'] = 'log' if self.state.x_log else 'linear'
state_dict['y_log_str'] = 'log' if self.state.y_log else 'linear'
+ state_dict['show_axes'] = 'on' if self.state.show_axes else 'off'
+ state_dict['margin'] = 'ax.set_position([0, 0, 1, 1])' if not self.state.show_axes else ''
return [], SCRIPT_FOOTER.format(**state_dict)
def _script_legend(self):