diff --git a/CHANGES.md b/CHANGES.md
index 653b1754c..38919d6a9 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -6,6 +6,9 @@ v0.6 (unreleased)
* Added a GUI plugin manager in the 'Plugins' menu. [#682]
+* Added an option to specify whether to use an automatic aspect ratio for image
+ data or whether to enforce square pixels. [#717]
+
* Data factories can now be given priorities to determine which ones should
take precedence in ambiguous cases. The ``set_default_factory`` and
``get_default_factory`` functions are now deprecated since it is possible to
diff --git a/glue/clients/image_client.py b/glue/clients/image_client.py
index 8f8260e53..d52a72f2a 100644
--- a/glue/clients/image_client.py
+++ b/glue/clients/image_client.py
@@ -36,8 +36,10 @@ def result(*args, **kwargs):
class ImageClient(VizClient):
+
display_data = CallbackProperty(None)
display_attribute = CallbackProperty(None)
+ display_aspect = CallbackProperty(None)
def __init__(self, data, artist_container=None):
@@ -327,14 +329,17 @@ def _update_data_plot(self, relim=False, force=False):
self._view = view
for a in list(self.artists):
- if (not isinstance(a, ScatterLayerBase)) and \
- a.layer.data is not self.display_data:
+ if (not isinstance(a, ScatterLayerBase) and
+ a.layer.data is not self.display_data):
self.artists.remove(a)
else:
- a.update(view, transpose)
+ if isinstance(a, ScatterLayerBase):
+ a.update(view, transpose)
+ else:
+ a.update(view, transpose, aspect=self.display_aspect)
for a in self.artists[self.display_data]:
meth = a.update if not force else a.force_update
- meth(view, transpose=transpose)
+ meth(view, transpose=transpose, aspect=self.display_aspect)
def _update_subset_single(self, s, redraw=False, force=False):
"""
@@ -464,6 +469,10 @@ def rgb_mode(self, enable=None):
self._redraw()
return result
+ def update_aspect(self):
+ self._update_data_plot(relim=True)
+ self._redraw()
+
def add_layer(self, layer):
if layer in self.artists:
return self.artists[layer][0]
diff --git a/glue/clients/layer_artist.py b/glue/clients/layer_artist.py
index d61cfab22..d9a5e2b94 100644
--- a/glue/clients/layer_artist.py
+++ b/glue/clients/layer_artist.py
@@ -452,7 +452,11 @@ def _update_clip(self, att):
data = small_view_array(self._override_image)
self.norm.update_clip(data)
- def update(self, view, transpose=False):
+ def update(self, view, transpose=False, aspect=None):
+
+ if aspect is None:
+ aspect = 'equal'
+
self.clear()
views = view_cascade(self.layer, view)
artists = []
@@ -470,7 +474,7 @@ def update(self, view, transpose=False):
interpolation='nearest',
origin='lower',
extent=extent, zorder=0))
- self._axes.set_aspect('equal', adjustable='datalim')
+ self._axes.set_aspect(aspect, adjustable='datalim')
self.artists = artists
self._sync_style()
@@ -541,8 +545,13 @@ def set_norm(self, *args, **kwargs):
self.norm = self.bnorm
self.bnorm = spr(*args, **kwargs)
- def update(self, view=None, transpose=False):
+ def update(self, view=None, transpose=False, aspect=None):
+
self.clear()
+
+ if aspect is None:
+ aspect = 'equal'
+
if self.r is None or self.g is None or self.b is None:
return
@@ -591,7 +600,7 @@ def update(self, view=None, transpose=False):
interpolation='nearest',
origin='lower',
extent=extent, zorder=0))
- self._axes.set_aspect('equal', adjustable='datalim')
+ self._axes.set_aspect(aspect, adjustable='datalim')
self.artists = artists
self._sync_style()
diff --git a/glue/qt/ui/imagewidget.ui b/glue/qt/ui/imagewidget.ui
index b1037d1dd..923fef2d9 100644
--- a/glue/qt/ui/imagewidget.ui
+++ b/glue/qt/ui/imagewidget.ui
@@ -6,8 +6,8 @@
0
0
- 299
- 331
+ 351
+ 279
@@ -51,18 +51,15 @@
10
-
-
-
- 2
-
-
-
-
+
+
-
+
- Data
+ Attribute
- -
+
-
@@ -78,10 +75,56 @@
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Set which attribute of the data to display
+
+
+ QComboBox::AdjustToMinimumContentsLength
+
+
+
+ -
+
+
+ Data
+
+
+
+ -
+
+
+ Aspect
+
+
+
+ -
+
+
-
-
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
-
@@ -105,38 +148,24 @@
-
-
- -
-
-
- 2
-
-
-
-
-
- Attribute
-
-
-
-
-
-
-
- 0
- 0
-
+
+
+ Qt::Horizontal
-
- Set which attribute of the data to display
+
+
+ 40
+ 20
+
-
- QComboBox::AdjustToMinimumContentsLength
-
-
+
+ -
+
+
-
@@ -144,22 +173,6 @@
- -
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 5
- 5
-
-
-
-
diff --git a/glue/qt/widgets/image_widget.py b/glue/qt/widgets/image_widget.py
index 75af8e86f..fcef7229c 100644
--- a/glue/qt/widgets/image_widget.py
+++ b/glue/qt/widgets/image_widget.py
@@ -48,6 +48,8 @@ class ImageWidgetBase(DataViewer):
'Current attribute')
data = CurrentComboProperty('ui.displayDataCombo',
'Current data')
+ aspect_ratio = CurrentComboProperty('ui.aspectCombo',
+ 'Aspect ratio for image')
rgb_mode = ButtonProperty('ui.rgb',
'RGB Mode?')
rgb_viz = Pointer('ui.rgb_options.rgb_visible')
@@ -74,6 +76,9 @@ def _setup_widgets(self):
self.ui.slice_layout.addWidget(self.ui.slice)
self._tweak_geometry()
+ self.ui.aspectCombo.addItem("Square Pixels", userData='equal')
+ self.ui.aspectCombo.addItem("Automatic", userData='auto')
+
def make_client(self):
""" Instantiate and return an ImageClient subclass """
raise NotImplementedError()
@@ -215,10 +220,12 @@ def _connect(self):
# sync window title to data/attribute
add_callback(self.client, 'display_data', nonpartial(self.update_window_title))
add_callback(self.client, 'display_attribute', nonpartial(self.update_window_title))
+ add_callback(self.client, 'display_aspect', nonpartial(self.client.update_aspect))
# sync data/attribute combos with client properties
connect_current_combo(self.client, 'display_data', self.ui.displayDataCombo)
connect_current_combo(self.client, 'display_attribute', self.ui.attributeComboBox)
+ connect_current_combo(self.client, 'display_aspect', self.ui.aspectCombo)
@defer_draw
def _update_rgb_console(self, is_monochrome):