)
- def _swap(x, s, i, j):
- x[i], x[j] = x[j], x[i]
- s[i], s[j] = s[j], s[i]
-
- _swap(dims, s, ind, 0)
- _swap(dims, s, s.index('y'), 1)
- _swap(dims, s, s.index('x'), 2)
-
- cube = cube.transpose(dims)
-
- if cube_wcs is not None:
- cube_wcs = cube_wcs.sub([data.ndim - nx for nx in dims[::-1]])
-
- # slice down from >3D to 3D if needed
- s = tuple([slice(None)] * 3 + [slc[d] for d in dims[3:]])
- cube = cube[s]
-
- # sample cube
- spacing = 1 # pixel
- x, y = [np.round(_x).astype(int) for _x in p.sample_points(spacing)]
-
- try:
- result = extract_pv_slice(cube, path=p, wcs=cube_wcs, order=0)
- wcs = WCS(result.header)
- except Exception: # sometimes pvextractor complains due to wcs. Try to recover
- result = extract_pv_slice(cube, path=p, wcs=None, order=0)
- wcs = None
-
- data = result.data
-
- return data, x, y, wcs
-
-
-def _slice_index(data, slc):
- """
- The axis over which to extract PV slices
- """
- for i in range(len(slc)):
- if np.isreal(slc[i]):
- return i
- raise ValueError("Could not find slice index with slc={0}".format(slc))
-
-
-def _slice_label(data, slc):
- """
- Returns a formatted axis label corresponding to the slice dimension
- in a PV slice
-
- :param data: Data that slice is extracted from
- :param slc: orientation in the image widget from which the PV slice
- was defined
- """
- idx = _slice_index(data, slc)
- if getattr(data, 'coords') is None:
- return data.pixel_component_ids[idx].label
- else:
- return axis_label(data.coords, idx)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.plugins.tools.pv_slicer.qt.pv_slicer is deprecated, use glue_qt.plugins.tools.pv_slicer.pv_slicer instead', GlueDeprecationWarning)
+from glue_qt.plugins.tools.pv_slicer.pv_slicer import * # noqa
diff --git a/glue/plugins/tools/pv_slicer/qt/tests/__init__.py b/glue/plugins/tools/pv_slicer/qt/tests/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/glue/plugins/tools/pv_slicer/qt/tests/test_pv_slicer.py b/glue/plugins/tools/pv_slicer/qt/tests/test_pv_slicer.py
deleted file mode 100644
index 5fe1b5c6a..000000000
--- a/glue/plugins/tools/pv_slicer/qt/tests/test_pv_slicer.py
+++ /dev/null
@@ -1,154 +0,0 @@
-import numpy as np
-from unittest.mock import MagicMock
-from numpy.testing import assert_allclose
-
-from glue.core import Data
-from glue.core.coordinates import IdentityCoordinates
-from glue.viewers.image.qt import StandaloneImageViewer, ImageViewer
-from glue.tests.helpers import requires_astropy, requires_scipy
-from glue.app.qt import GlueApplication
-from glue.utils.qt import process_events
-
-from ..pv_slicer import _slice_from_path, _slice_label, _slice_index, PVSliceWidget
-
-
-@requires_astropy
-@requires_scipy
-class TestSliceExtraction(object):
-
- def setup_method(self, method):
- self.x = np.random.random((2, 3, 4))
- self.d = Data(x=self.x)
-
- def test_constant_y(self):
-
- slc = (0, 'y', 'x')
- x = [-0.5, 3.5]
- y = [0, 0]
- s = _slice_from_path(x, y, self.d, 'x', slc)[0]
- assert_allclose(s, self.x[:, 0, :])
-
- def test_constant_x(self):
-
- slc = (0, 'y', 'x')
- y = [-0.5, 2.5]
- x = [0, 0]
- s = _slice_from_path(x, y, self.d, 'x', slc)[0]
- assert_allclose(s, self.x[:, :, 0])
-
- def test_transpose(self):
- slc = (0, 'x', 'y')
- y = [-0.5, 3.5]
- x = [0, 0]
- s = _slice_from_path(x, y, self.d, 'x', slc)[0]
- assert_allclose(s, self.x[:, 0, :])
-
-
-def test_slice_label():
- d = Data(x=np.zeros((2, 3, 4)), coords=IdentityCoordinates(n_dim=3))
- assert _slice_label(d, (0, 'y', 'x')) == 'World 0'
- assert _slice_label(d, ('y', 0, 'x')) == 'World 1'
- assert _slice_label(d, ('y', 'x', 0)) == 'World 2'
-
-
-def test_slice_label_nocoords():
- d = Data(x=np.zeros((2, 3, 4)))
- assert _slice_label(d, (0, 'y', 'x')) == 'Pixel Axis 0 [z]'
- assert _slice_label(d, ('y', 0, 'x')) == 'Pixel Axis 1 [y]'
- assert _slice_label(d, ('y', 'x', 0)) == 'Pixel Axis 2 [x]'
-
-
-def test_slice_index():
- d = Data(x=np.zeros((2, 3, 4)))
- assert _slice_index(d, (0, 'y', 'x')) == 0
- assert _slice_index(d, ('y', 0, 'x')) == 1
-
-
-class TestStandaloneImageViewer(object):
-
- def setup_method(self, method):
- im = np.random.random((3, 3))
- self.w = StandaloneImageViewer(im)
-
- def teardown_method(self, method):
- self.w.close()
-
- def test_set_cmap(self):
- cm_mode = self.w.toolbar.tools['image:colormap']
- act = cm_mode.menu_actions()[1]
- act.trigger()
- assert self.w._composite.layers['image']['cmap'] is act.cmap
-
- def test_double_set_image(self):
- assert len(self.w._axes.images) == 1
- self.w.set_image(np.zeros((3, 3)))
- assert len(self.w._axes.images) == 1
-
-
-class MockImageViewer(object):
-
- def __init__(self, slice, data):
- self.slice = slice
- self.data = data
- self.wcs = None
- self.state = MagicMock()
-
-
-class TestPVSliceWidget(object):
-
- def setup_method(self, method):
-
- self.d = Data(x=np.zeros((2, 3, 4)))
- self.slc = (0, 'y', 'x')
- self.image = MockImageViewer(self.slc, self.d)
- self.w = PVSliceWidget(image=np.zeros((3, 4)), wcs=None, image_viewer=self.image)
-
- def teardown_method(self, method):
- self.w.close()
-
- def test_basic(self):
- pass
-
-
-class TestPVSliceTool(object):
-
- def setup_method(self, method):
- self.cube = Data(label='cube', x=np.arange(1000).reshape((5, 10, 20)))
- self.application = GlueApplication()
- self.application.data_collection.append(self.cube)
- self.viewer = self.application.new_data_viewer(ImageViewer)
- self.viewer.add_data(self.cube)
-
- def teardown_method(self, method):
- self.viewer.close()
- self.viewer = None
- self.application.close()
- self.application = None
-
- @requires_astropy
- @requires_scipy
- def test_basic(self):
-
- self.viewer.toolbar.active_tool = 'slice'
-
- self.viewer.axes.figure.canvas.draw()
- process_events()
-
- x, y = self.viewer.axes.transData.transform([[0.9, 4]])[0]
- self.viewer.axes.figure.canvas.button_press_event(x, y, 1)
- x, y = self.viewer.axes.transData.transform([[7.2, 6.6]])[0]
- self.viewer.axes.figure.canvas.button_press_event(x, y, 1)
-
- process_events()
-
- assert len(self.application.tab().subWindowList()) == 1
-
- self.viewer.axes.figure.canvas.key_press_event('enter')
-
- process_events()
-
- assert len(self.application.tab().subWindowList()) == 2
-
- pv_widget = self.application.tab().subWindowList()[1].widget()
- assert pv_widget._x.shape == (6,)
- assert pv_widget._y.shape == (6,)
diff --git a/glue/qglue.py b/glue/qglue.py
index 1133e48f7..66dc0e175 100644
--- a/glue/qglue.py
+++ b/glue/qglue.py
@@ -1,216 +1,18 @@
-"""
-Utility function to load a variety of python objects into glue
-"""
+import warnings
+from glue.utils.error import GlueDeprecationWarning
-# Note: this is imported with Glue. We want
-# to minimize imports so that utilities like glue-deps
-# can run on systems with missing dependencies
+warnings.warn('Importing from glue.qglue is deprecated, use glue_qt.qglue instead', GlueDeprecationWarning)
-import sys
-from contextlib import contextmanager
+from glue_qt.qglue import * # noqa
-import numpy as np
-from glue.config import qglue_parser
+def parse_data(*args, **kwargs):
+ warnings.warn('glue.qglue.parse_data is deprecated, use glue.core.parsers.parse_data instead', GlueDeprecationWarning)
+ from glue.core.parsers import parse_data
+ return parse_data(*args, **kwargs)
-try:
- from glue.core import BaseData, Data
-except ImportError:
- # let qglue import, even though this won't work
- # qglue will throw an ImportError
- BaseData = Data = None
-
-__all__ = ['qglue']
-
-
-@contextmanager
-def restore_io():
- stdin = sys.stdin
- stdout = sys.stdout
- stderr = sys.stderr
- _in = sys.__stdin__
- _out = sys.__stdout__
- _err = sys.__stderr__
- try:
- yield
- finally:
- sys.stdin = stdin
- sys.stdout = stdout
- sys.stderr = stderr
- sys.__stdin__ = _in
- sys.__stdout__ = _out
- sys.__stderr__ = _err
-
-
-@qglue_parser(dict)
-def _parse_data_dict(data, label):
- result = Data(label=label)
- for label, component in data.items():
- result.add_component(component, label)
- return [result]
-
-
-@qglue_parser(np.recarray)
-def _parse_data_recarray(data, label):
- kwargs = dict((n, data[n]) for n in data.dtype.names)
- return [Data(label=label, **kwargs)]
-
-
-@qglue_parser(BaseData)
-def _parse_data_glue_data(data, label):
- if isinstance(data, Data):
- data.label = label
- return [data]
-
-
-@qglue_parser(np.ndarray)
-def _parse_data_numpy(data, label):
- return [Data(**{label: data, 'label': label})]
-
-
-@qglue_parser(list)
-def _parse_data_list(data, label):
- return [Data(**{label: data, 'label': label})]
-
-
-@qglue_parser(str)
-def _parse_data_path(path, label):
- from glue.core.data_factories import load_data, as_list
-
- data = load_data(path)
- for d in as_list(data):
- d.label = label
- return as_list(data)
-
-
-def parse_data(data, label):
-
- # First try new data translation layer
-
- from glue.config import data_translator
-
- try:
- handler, preferred = data_translator.get_handler_for(data)
- except TypeError:
- pass
- else:
- data = handler.to_data(data)
- data.label = label
- data._preferred_translation = preferred
- return [data]
-
- # Then try legacy 'qglue_parser' infrastructure
-
- for item in qglue_parser:
-
- data_class = item.data_class
- parser = item.parser
- if isinstance(data, data_class):
- try:
- return parser(data, label)
- except Exception as e:
- raise ValueError("Invalid format for data '%s'\n\n%s" %
- (label, e))
-
- raise TypeError("Invalid data description: %s" % data)
-
-
-def parse_links(dc, links):
- from glue.core.link_helpers import MultiLink
- from glue.core import ComponentLink
-
- data = dict((d.label, d) for d in dc)
- result = []
-
- def find_cid(s):
- dlabel, clabel = s.split('.')
- d = data[dlabel]
- c = d.find_component_id(clabel)
- if c is None:
- raise ValueError("Invalid link (no component named %s)" % s)
- return c
-
- for link in links:
- f, t = link[0:2] # from and to component names
- u = u2 = None
- if len(link) >= 3: # forward translation function
- u = link[2]
- if len(link) == 4: # reverse translation function
- u2 = link[3]
-
- # component names -> component IDs
- if isinstance(f, str):
- f = [find_cid(f)]
- else:
- f = [find_cid(item) for item in f]
-
- if isinstance(t, str):
- t = find_cid(t)
- result.append(ComponentLink(f, t, u))
- else:
- t = [find_cid(item) for item in t]
- result += MultiLink(f, t, u, u2)
-
- return result
-
-
-def qglue(**kwargs):
- """
- Quickly send python variables to Glue for visualization.
-
- The generic calling sequence is::
-
- qglue(label1=data1, label2=data2, ..., [links=links])
-
- The kewyords label1, label2, ... can be named anything besides ``links``
-
- data1, data2, ... can be in many formats:
- * A pandas data frame
- * A path to a file
- * A numpy array, or python list
- * A numpy rec array
- * A dictionary of numpy arrays with the same shape
- * An astropy Table
-
- ``Links`` is an optional list of link descriptions, each of which has
- the format: ([left_ids], [right_ids], forward, backward)
-
- Each ``left_id``/``right_id`` is a string naming a component in a dataset
- (i.e., ``data1.x``). ``forward`` and ``backward`` are functions which
- map quantities on the left to quantities on the right, and vice
- versa. `backward` is optional
-
- Examples::
-
- balls = {'kg': [1, 2, 3], 'radius_cm': [10, 15, 30]}
- cones = {'lbs': [5, 3, 3, 1]}
- def lb2kg(lb):
- return lb / 2.2
- def kg2lb(kg):
- return kg * 2.2
-
- links = [(['balls.kg'], ['cones.lbs'], lb2kg, kg2lb)]
- qglue(balls=balls, cones=cones, links=links)
-
- :returns: A :class:`~glue.app.qt.application.GlueApplication` object
- """
- from glue.core import DataCollection
- from glue.app.qt import GlueApplication
- from glue.dialogs.autolinker.qt import run_autolinker
-
- links = kwargs.pop('links', None)
-
- dc = DataCollection()
- for label, data in kwargs.items():
- dc.extend(parse_data(data, label))
-
- if links is not None:
- dc.add_link(parse_links(dc, links))
-
- with restore_io():
- ga = GlueApplication(dc)
- run_autolinker(dc)
- ga.start()
-
- return ga
+def parse_links(*args, **kwargs):
+ warnings.warn('glue.qglue.parse_links is deprecated, use glue.core.parsers.parse_links instead', GlueDeprecationWarning)
+ from glue.core.parsers import parse_links
+ return parse_links(*args, **kwargs)
diff --git a/glue/tests/data/__init__.py b/glue/tests/data/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/glue/tests/data/double_tables.fits b/glue/tests/data/double_tables.fits
deleted file mode 100644
index 1c382e70d..000000000
Binary files a/glue/tests/data/double_tables.fits and /dev/null differ
diff --git a/glue/tests/data/glue_v0.10_table.glu b/glue/tests/data/glue_v0.10_table.glu
deleted file mode 100644
index 25baa1c82..000000000
--- a/glue/tests/data/glue_v0.10_table.glu
+++ /dev/null
@@ -1,365 +0,0 @@
-{
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoBAAAAAAAAAAIAAAAAAAAAAwAAAAAAAAA="
- },
- "units": ""
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoEAAAAAAAAAAUAAAAAAAAABgAAAAAAAAA="
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates_0",
- "frm": [
- "Pixel Axis 0 [x]_0"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0_0"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates_0",
- "frm": [
- "World 0_0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]_0"
- ]
- },
- "CoordinateComponentLink_1": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponentLink_2": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]"
- ]
- },
- "CoordinateComponentLink_3": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [x]_1"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0_1"
- ]
- },
- "CoordinateComponentLink_4": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0_1"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]_1"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "Coordinates_0": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "x",
- "Pixel Axis 0 [x]",
- "World 0",
- "y"
- ],
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component_0"
- ],
- "data": [
- "data"
- ],
- "groups": [
- "Subset 1_0",
- "Subset 2_0"
- ],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0",
- "CoordinateComponentLink_1",
- "CoordinateComponentLink_2",
- "CoordinateComponentLink_3",
- "CoordinateComponentLink_4"
- ],
- "subset_group_count": 2
- },
- "ElementSubsetState": {
- "_type": "glue.core.subset.ElementSubsetState",
- "data_uuid": "ca8ae9d2-170d-482a-bb93-4f8e1b4b1ddd",
- "indices": [
- 0,
- 1
- ]
- },
- "ElementSubsetState_0": {
- "_type": "glue.core.subset.ElementSubsetState",
- "data_uuid": "ca8ae9d2-170d-482a-bb93-4f8e1b4b1ddd",
- "indices": [
- 1
- ]
- },
- "Pixel Axis 0 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [x]"
- },
- "Pixel Axis 0 [x]_0": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [x]"
- },
- "Pixel Axis 0 [x]_1": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [x]"
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "Subset 1": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 1_0",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- }
- },
- "Subset 1_0": {
- "_type": "glue.core.subset_group.SubsetGroup",
- "label": "Subset 1",
- "state": "ElementSubsetState",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- },
- "subsets": [
- "Subset 1"
- ]
- },
- "Subset 2": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 2_0",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#33a02c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- }
- },
- "Subset 2_0": {
- "_type": "glue.core.subset_group.SubsetGroup",
- "label": "Subset 2",
- "state": "ElementSubsetState_0",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#33a02c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- },
- "subsets": [
- "Subset 2"
- ]
- },
- "TableWidget": {
- "_type": "glue.viewers.table.qt.viewer_widget.TableWidget",
- "layers": [
- {
- "_type": "glue.viewers.table.qt.viewer_widget.TableLayerArtist",
- "layer": "data",
- "visible": true,
- "zorder": 1
- },
- {
- "_type": "glue.viewers.table.qt.viewer_widget.TableLayerArtist",
- "layer": "Subset 1",
- "visible": true,
- "zorder": 2
- },
- {
- "_type": "glue.viewers.table.qt.viewer_widget.TableLayerArtist",
- "layer": "Subset 2",
- "visible": true,
- "zorder": 3
- }
- ],
- "pos": [
- 0,
- 0
- ],
- "properties": {},
- "session": "Session",
- "size": [
- 640,
- 480
- ]
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "World 0_0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "World 0_1": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue.plugins.tools.pv_slicer",
- "glue_vispy_viewers.scatter",
- "glue_vispy_viewers.volume",
- "glue.core.data_exporters",
- "glue.plugins.tools.spectrum_tool",
- "glue.viewers.table",
- "glue.plugins.coordinate_helpers",
- "glue.plugins.exporters.plotly",
- "glue.viewers.image",
- "glue.viewers.histogram",
- "glue.viewers.scatter",
- "glue_ginga",
- "glue.plugins.export_d3po"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- [
- "TableWidget"
- ]
- ]
- },
- "data": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "x",
- "Component"
- ],
- [
- "Pixel Axis 0 [x]",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "y",
- "Component_0"
- ]
- ],
- "coords": "Coordinates",
- "label": "data",
- "primary_owner": [
- "x",
- "Pixel Axis 0 [x]",
- "World 0",
- "y"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "#595959",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [
- "Subset 1",
- "Subset 2"
- ],
- "uuid": "ca8ae9d2-170d-482a-bb93-4f8e1b4b1ddd"
- },
- "x": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "x"
- },
- "y": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "y"
- }
-}
\ No newline at end of file
diff --git a/glue/tests/data/glue_v0.7_pixel_roi_selection.glu b/glue/tests/data/glue_v0.7_pixel_roi_selection.glu
deleted file mode 100644
index 6abbc4730..000000000
--- a/glue/tests/data/glue_v0.7_pixel_roi_selection.glu
+++ /dev/null
@@ -1,363 +0,0 @@
-{
- "CoordinateComponent_2": {
- "world": true,
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1
- },
- "CoordinateComponent_1": {
- "world": true,
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0
- },
- "CoordinateComponent_0": {
- "world": false,
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "session": "Session",
- "data": "DataCollection",
- "viewers": [
- [
- "ImageWidget"
- ]
- ],
- "plugins": [
- "glue.plugins.tools.pv_slicer",
- "glue.viewers.histogram",
- "glue.plugins.export_plotly",
- "glue.plugins.export_d3po",
- "glue.viewers.image",
- "glue.plugins.tools.spectrum_tool",
- "glue.viewers.scatter",
- "glue.plugins.coordinate_helpers"
- ]
- },
- "1_0": {
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "color": "#e31a1c",
- "markersize": 7,
- "marker": "o",
- "alpha": 0.5,
- "linewidth": 1,
- "linestyle": "solid"
- },
- "group": "1",
- "_type": "glue.core.subset_group.GroupedSubset"
- },
- "World 1": {
- "hidden": true,
- "_type": "glue.core.component_id.ComponentID",
- "label": "World 1"
- },
- "image_0": {
- "hidden": false,
- "_type": "glue.core.component_id.ComponentID",
- "label": "image"
- },
- "CoordinateComponent": {
- "world": false,
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0
- },
- "Component": {
- "units": "None",
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGY4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsIDIpLCB9ICAgICAgICAgIAoAAAAAAADwPwAAAAAAAPA/AAAAAAAA8D8AAAAAAADwPwAAAAAAAPA/AAAAAAAA8D8="
- }
- },
- "1": {
- "_type": "glue.core.subset_group.SubsetGroup",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "color": "#e31a1c",
- "markersize": 7,
- "marker": "o",
- "alpha": 0.5,
- "linewidth": 1,
- "linestyle": "solid"
- },
- "state": "RoiSubsetState",
- "subsets": [
- "1_0"
- ],
- "label": "1"
- },
- "ImageWidget": {
- "layers": [
- {
- "visible": true,
- "layer": "image",
- "zorder": 1,
- "_type": "glue.viewers.image.layer_artist.ImageLayerArtist",
- "norm": "DS9Normalize"
- },
- {
- "visible": true,
- "layer": "1_0",
- "zorder": 2,
- "_type": "glue.viewers.image.layer_artist.SubsetImageLayerArtist"
- }
- ],
- "_type": "glue.viewers.image.qt.viewer_widget.ImageWidget",
- "pos": [
- 0,
- 0
- ],
- "session": "Session",
- "properties": {
- "rgb_viz": [
- true,
- true,
- true
- ],
- "ratt": null,
- "rgb_mode": false,
- "gatt": null,
- "attribute": "image_0",
- "batt": null,
- "slice": [
- "y",
- "x"
- ],
- "data": "image"
- },
- "size": [
- 600,
- 400
- ]
- },
- "CoordinateComponentLink_2": {
- "index": 1,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel y",
- "Pixel x"
- ],
- "to": [
- "World 1"
- ],
- "pix2world": true,
- "coords": "Coordinates"
- },
- "CoordinateComponentLink": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0",
- "World 1"
- ],
- "to": [
- "Pixel y"
- ],
- "pix2world": false,
- "coords": "Coordinates"
- },
- "image": {
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "color": "#7f7f7f",
- "markersize": 3,
- "marker": "o",
- "alpha": 0.5,
- "linewidth": 1,
- "linestyle": "solid"
- },
- "_protocol": 3,
- "subsets": [
- "1_0"
- ],
- "_type": "glue.core.data.Data",
- "label": "image",
- "coords": "Coordinates",
- "components": [
- [
- "image_0",
- "Component"
- ],
- [
- "Pixel y",
- "CoordinateComponent"
- ],
- [
- "Pixel x",
- "CoordinateComponent_0"
- ],
- [
- "World 0",
- "CoordinateComponent_1"
- ],
- [
- "World 1",
- "CoordinateComponent_2"
- ]
- ],
- "_key_joins": []
- },
- "World 0": {
- "hidden": true,
- "_type": "glue.core.component_id.ComponentID",
- "label": "World 0"
- },
- "RoiSubsetState": {
- "roi": "PolygonalROI",
- "_type": "glue.core.subset.RoiSubsetState",
- "xatt": "Pixel x",
- "yatt": "Pixel y"
- },
- "Pixel y": {
- "hidden": true,
- "_type": "glue.core.component_id.ComponentID",
- "label": "Pixel y"
- },
- "Pixel x": {
- "hidden": true,
- "_type": "glue.core.component_id.ComponentID",
- "label": "Pixel x"
- },
- "PolygonalROI": {
- "vx": [
- 0.523465703971119,
- 0.523465703971119,
- 0.523465703971119,
- 0.523465703971119,
- 0.5451263537906135,
- 0.5776173285198554,
- 0.6642599277978336,
- 0.8158844765342956,
- 0.9675090252707577,
- 1.1841155234657035,
- 1.335740072202166,
- 1.4765342960288805,
- 1.5631768953068592,
- 1.628158844765343,
- 1.7039711191335734,
- 1.7039711191335734,
- 1.7039711191335734,
- 1.6931407942238268,
- 1.628158844765343,
- 1.5415162454873643,
- 1.454873646209386,
- 1.3574007220216604,
- 1.2599277978339347,
- 1.162454873646209,
- 1.0649819494584833,
- 0.9675090252707577,
- 0.8808664259927794,
- 0.7942238267148012,
- 0.707581227436823,
- 0.6425992779783392,
- 0.5992779783393498
- ],
- "vy": [
- 1.9765342960288808,
- 1.9548736462093863,
- 1.868231046931408,
- 1.7382671480144405,
- 1.5108303249097472,
- 1.4133574007220215,
- 1.2942238267148014,
- 1.2075812274368232,
- 1.1859205776173285,
- 1.1859205776173285,
- 1.1859205776173285,
- 1.2075812274368232,
- 1.2184115523465704,
- 1.2509025270758123,
- 1.3375451263537905,
- 1.4891696750902528,
- 1.7707581227436824,
- 2.0090252707581224,
- 2.279783393501805,
- 2.4530685920577615,
- 2.5288808664259927,
- 2.583032490974729,
- 2.6263537906137184,
- 2.6696750902527073,
- 2.723826714801444,
- 2.734657039711191,
- 2.734657039711191,
- 2.6805054151624548,
- 2.6046931407942235,
- 2.5288808664259927,
- 2.4422382671480145
- ],
- "_type": "glue.core.roi.PolygonalROI"
- },
- "CoordinateComponentLink_1": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel y",
- "Pixel x"
- ],
- "to": [
- "World 0"
- ],
- "pix2world": true,
- "coords": "Coordinates"
- },
- "CoordinateComponentLink_0": {
- "index": 1,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0",
- "World 1"
- ],
- "to": [
- "Pixel x"
- ],
- "pix2world": false,
- "coords": "Coordinates"
- },
- "DS9Normalize": {
- "vmax": 1.0,
- "_type": "glue.viewers.image.ds9norm.DS9Normalize",
- "bias": 0.5,
- "vmin": 1.0,
- "clip_hi": 95.0,
- "stretch": "arcsinh",
- "clip_lo": 5.0,
- "contrast": 1.0
- },
- "DataCollection": {
- "_type": "glue.core.data_collection.DataCollection",
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "CoordinateComponent_1",
- "CoordinateComponent_2"
- ],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0",
- "CoordinateComponentLink_1",
- "CoordinateComponentLink_2"
- ],
- "_protocol": 2,
- "groups": [
- "1"
- ],
- "cids": [
- "image_0",
- "Pixel y",
- "Pixel x",
- "World 0",
- "World 1"
- ],
- "data": [
- "image"
- ]
- },
- "Session": {
- "_type": "glue.core.session.Session"
- }
-}
\ No newline at end of file
diff --git a/glue/tests/data/load_log_0.glu b/glue/tests/data/load_log_0.glu
deleted file mode 100644
index ffd25caad..000000000
--- a/glue/tests/data/load_log_0.glu
+++ /dev/null
@@ -1,164 +0,0 @@
-{
- "Component": {
- "_type": "glue.core.component.Component",
- "log": "LoadLog",
- "log_item": 0
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "log": "LoadLog",
- "log_item": 3
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0",
- "b"
- ],
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component_0"
- ],
- "data": [
- "simple"
- ],
- "groups": [],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0"
- ],
- "subset_group_count": 0
- },
- "LoadLog": {
- "_type": "glue.core.data_factories.helpers.LoadLog",
- "factory": {
- "_type": "types.FunctionType",
- "function": "glue.core.data_factories.helpers.auto_data"
- },
- "kwargs": [
- []
- ],
- "path": "{DATA_PATH}simple.csv"
- },
- "Pixel Axis 0 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [x]"
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- []
- ]
- },
- "a": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "a"
- },
- "b": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "b"
- },
- "simple": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "a",
- "Component"
- ],
- [
- "Pixel Axis 0 [x]",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "b",
- "Component_0"
- ]
- ],
- "coords": "Coordinates",
- "label": "simple",
- "primary_owner": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0",
- "b"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "0.35",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [],
- "uuid": "fd317c94-7a6a-4ac2-b024-17e44bde3cb8"
- }
-}
diff --git a/glue/tests/data/load_log_1.glu b/glue/tests/data/load_log_1.glu
deleted file mode 100644
index 90bb2f634..000000000
--- a/glue/tests/data/load_log_1.glu
+++ /dev/null
@@ -1,165 +0,0 @@
-{
- "Component": {
- "_type": "glue.core.component.Component",
- "log": "LoadLog",
- "log_item": 2
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "log": "LoadLog",
- "log_item": 3
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "Pixel Axis 0 [x]",
- "World 0",
- "a",
- "b"
- ],
- "components": [
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component",
- "Component_0"
- ],
- "data": [
- "simple"
- ],
- "groups": [],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0"
- ],
- "subset_group_count": 0
- },
- "LoadLog": {
- "_protocol": 1,
- "_type": "glue.core.data_factories.helpers.LoadLog",
- "factory": {
- "_type": "types.FunctionType",
- "function": "glue.core.data_factories.helpers.auto_data"
- },
- "kwargs": [
- []
- ],
- "path": "{DATA_PATH}simple.csv"
- },
- "Pixel Axis 0 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [x]"
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- []
- ]
- },
- "a": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "a"
- },
- "b": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "b"
- },
- "simple": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "Pixel Axis 0 [x]",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "a",
- "Component"
- ],
- [
- "b",
- "Component_0"
- ]
- ],
- "coords": "Coordinates",
- "label": "simple",
- "primary_owner": [
- "Pixel Axis 0 [x]",
- "World 0",
- "a",
- "b"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "0.35",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [],
- "uuid": "741368cc-0826-4e8e-aa11-9e8ac0a093cd"
- }
-}
diff --git a/glue/tests/data/session_coordinate_links_013.glu b/glue/tests/data/session_coordinate_links_013.glu
deleted file mode 100644
index f52ee9ef8..000000000
--- a/glue/tests/data/session_coordinate_links_013.glu
+++ /dev/null
@@ -1,335 +0,0 @@
-{
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQB2AHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAoBAAAAAAAAAAIAAAAAAAAAAwAAAAAAAAA="
- },
- "units": ""
- },
- "ComponentLink": {
- "_type": "glue.core.component_link.ComponentLink",
- "frm": [
- "x_0",
- "y_0"
- ],
- "inverse": null,
- "to": [
- "x"
- ],
- "using": {
- "_type": "glue.core.link_helpers.PartialResult",
- "func": {
- "_type": "types.MethodType",
- "instance": "Galactic_to_FK5",
- "method": "forward"
- },
- "index": 0
- }
- },
- "ComponentLink_0": {
- "_type": "glue.core.component_link.ComponentLink",
- "frm": [
- "x",
- "y"
- ],
- "inverse": null,
- "to": [
- "x_0"
- ],
- "using": {
- "_type": "glue.core.link_helpers.PartialResult",
- "func": {
- "_type": "types.MethodType",
- "instance": "Galactic_to_FK5",
- "method": "backward"
- },
- "index": 0
- }
- },
- "ComponentLink_1": {
- "_type": "glue.core.component_link.ComponentLink",
- "frm": [
- "x_0",
- "y_0"
- ],
- "inverse": null,
- "to": [
- "y"
- ],
- "using": {
- "_type": "glue.core.link_helpers.PartialResult",
- "func": {
- "_type": "types.MethodType",
- "instance": "Galactic_to_FK5",
- "method": "forward"
- },
- "index": 1
- }
- },
- "ComponentLink_2": {
- "_type": "glue.core.component_link.ComponentLink",
- "frm": [
- "x",
- "y"
- ],
- "inverse": null,
- "to": [
- "y_0"
- ],
- "using": {
- "_type": "glue.core.link_helpers.PartialResult",
- "func": {
- "_type": "types.MethodType",
- "instance": "Galactic_to_FK5",
- "method": "backward"
- },
- "index": 1
- }
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQB2AHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAoCAAAAAAAAAAMAAAAAAAAABAAAAAAAAAA="
- },
- "units": ""
- },
- "Component_1": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQB2AHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAoBAAAAAAAAAAIAAAAAAAAAAwAAAAAAAAA="
- },
- "units": ""
- },
- "Component_2": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQB2AHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAoCAAAAAAAAAAMAAAAAAAAABAAAAAAAAAA="
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "CoordinateComponent_1": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponent_2": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "Coordinates_0": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 4,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "Pixel Axis 0 [x]",
- "World 0",
- "x",
- "y",
- "Pixel Axis 0 [x]_0",
- "World 0_0",
- "x_0",
- "y_0"
- ],
- "components": [
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component",
- "Component_0",
- "CoordinateComponent_1",
- "CoordinateComponent_2",
- "Component_1",
- "Component_2"
- ],
- "data": [
- "data1",
- "data2"
- ],
- "groups": [],
- "links": [
- "ComponentLink",
- "ComponentLink_0",
- "ComponentLink_1",
- "ComponentLink_2"
- ],
- "subset_group_count": 0
- },
- "Galactic_to_FK5": {
- "_type": "glue.plugins.coordinate_helpers.link_helpers.Galactic_to_FK5",
- "cids": [
- "x_0",
- "y_0",
- "x",
- "y"
- ]
- },
- "Pixel Axis 0 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "label": "Pixel Axis 0 [x]"
- },
- "Pixel Axis 0 [x]_0": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "label": "Pixel Axis 0 [x]"
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "World 0"
- },
- "World 0_0": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "World 0"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue.plugins.tools",
- "glue.plugins.export_d3po",
- "glue.core.data_exporters",
- "mosviz",
- "glue.io.formats.fits",
- "glue.plugins.tools.pv_slicer",
- "glue.plugins.coordinate_helpers",
- "glue.plugins.data_factories.spectral_cube"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- []
- ]
- },
- "data1": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "Pixel Axis 0 [x]",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "x",
- "Component"
- ],
- [
- "y",
- "Component_0"
- ]
- ],
- "coords": "Coordinates",
- "label": "data1",
- "meta": {
- "_type": "collections.OrderedDict",
- "contents": {}
- },
- "primary_owner": [
- "Pixel Axis 0 [x]",
- "World 0",
- "x",
- "y"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "#919191",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [],
- "uuid": "4eb0477a-dc4c-4062-8245-4249124f66b0"
- },
- "data2": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "Pixel Axis 0 [x]_0",
- "CoordinateComponent_1"
- ],
- [
- "World 0_0",
- "CoordinateComponent_2"
- ],
- [
- "x_0",
- "Component_1"
- ],
- [
- "y_0",
- "Component_2"
- ]
- ],
- "coords": "Coordinates_0",
- "label": "data2",
- "meta": {
- "_type": "collections.OrderedDict",
- "contents": {}
- },
- "primary_owner": [
- "Pixel Axis 0 [x]_0",
- "World 0_0",
- "x_0",
- "y_0"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "#919191",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [],
- "uuid": "a0d5cba0-9770-4b38-8682-82c80854b109"
- },
- "x": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "x"
- },
- "x_0": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "x"
- },
- "y": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "y"
- },
- "y_0": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "y"
- }
-}
\ No newline at end of file
diff --git a/glue/tests/data/session_links.glu b/glue/tests/data/session_links.glu
deleted file mode 100644
index 7e68cf769..000000000
--- a/glue/tests/data/session_links.glu
+++ /dev/null
@@ -1,456 +0,0 @@
-{
- "World 0_0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 0"
- },
- "CoordinateComponent_2": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "CoordinateComponent_1": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "CoordinateComponent_0": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "Coordinates_0": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DerivedComponent": {
- "_type": "glue.core.data.DerivedComponent",
- "link": "ComponentLink"
- },
- "__main__": {
- "_type": "glue.qt.glue_application.GlueApplication",
- "session": "Session",
- "data": "DataCollection",
- "viewers": [
- []
- ]
- },
- "DerivedComponent_2": {
- "_type": "glue.core.data.DerivedComponent",
- "link": "ComponentLink_2"
- },
- "DerivedComponent_1": {
- "_type": "glue.core.data.DerivedComponent",
- "link": "ComponentLink_0"
- },
- "DerivedComponent_0": {
- "_type": "glue.core.data.DerivedComponent",
- "link": "ComponentLink_1"
- },
- "CoordinateComponent": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "ComponentLink": {
- "_type": "glue.core.component_link.ComponentLink",
- "inverse": null,
- "frm": [
- "l",
- "b"
- ],
- "to": [
- "ra"
- ],
- "using": {
- "index": 0,
- "_type": "glue.core.link_helpers.PartialResult",
- "func": {
- "function": "glue.external.aplpy.gal2fk5",
- "_type": "types.FunctionType"
- }
- },
- "hidden": false
- },
- "CoordinateComponentLink": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel Axis 0_0"
- ],
- "to": [
- "World 0_0"
- ],
- "pix2world": true,
- "coords": "Coordinates"
- },
- "ra": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "ra"
- },
- "ComponentLink_2": {
- "_type": "glue.core.component_link.ComponentLink",
- "inverse": null,
- "frm": [
- "ra",
- "dec"
- ],
- "to": [
- "b"
- ],
- "using": {
- "function": "glue.core.link_helpers.radec2glat",
- "_type": "types.FunctionType"
- },
- "hidden": false
- },
- "ComponentLink_1": {
- "_type": "glue.core.component_link.ComponentLink",
- "inverse": null,
- "frm": [
- "l",
- "b"
- ],
- "to": [
- "dec"
- ],
- "using": {
- "index": 1,
- "_type": "glue.core.link_helpers.PartialResult",
- "func": {
- "function": "glue.external.aplpy.gal2fk5",
- "_type": "types.FunctionType"
- }
- },
- "hidden": false
- },
- "World 0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 0"
- },
- "Pixel Axis 0_0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel Axis 0"
- },
- "Pixel Axis 0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel Axis 0"
- },
- "ComponentLink_3": {
- "_type": "glue.core.component_link.ComponentLink",
- "inverse": null,
- "frm": [
- "l",
- "b"
- ],
- "to": [
- "dec"
- ],
- "using": {
- "function": "glue.core.link_helpers.lb2dec",
- "_type": "types.FunctionType"
- },
- "hidden": false
- },
- "CoordinateComponentLink_2": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel Axis 0"
- ],
- "to": [
- "World 0"
- ],
- "pix2world": true,
- "coords": "Coordinates_0"
- },
- "CoordinateComponentLink_1": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0"
- ],
- "to": [
- "Pixel Axis 0"
- ],
- "pix2world": false,
- "coords": "Coordinates_0"
- },
- "Component": {
- "units": null,
- "_type": "glue.core.data.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoBAAAAAAAAAAIAAAAAAAAAAwAAAAAAAAA="
- }
- },
- "ComponentLink_6": {
- "_type": "glue.core.component_link.ComponentLink",
- "inverse": null,
- "frm": [
- "l",
- "b"
- ],
- "to": [
- "ra"
- ],
- "using": {
- "function": "glue.core.link_helpers.lb2ra",
- "_type": "types.FunctionType"
- },
- "hidden": false
- },
- "ComponentLink_5": {
- "_type": "glue.core.component_link.ComponentLink",
- "inverse": null,
- "frm": [
- "ra",
- "dec"
- ],
- "to": [
- "b"
- ],
- "using": {
- "index": 1,
- "_type": "glue.core.link_helpers.PartialResult",
- "func": {
- "function": "glue.external.aplpy.fk52gal",
- "_type": "types.FunctionType"
- }
- },
- "hidden": false
- },
- "ComponentLink_4": {
- "_type": "glue.core.component_link.ComponentLink",
- "inverse": null,
- "frm": [
- "ra",
- "dec"
- ],
- "to": [
- "l"
- ],
- "using": {
- "index": 0,
- "_type": "glue.core.link_helpers.PartialResult",
- "func": {
- "function": "glue.external.aplpy.fk52gal",
- "_type": "types.FunctionType"
- }
- },
- "hidden": false
- },
- "CoordinateComponentLink_0": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0_0"
- ],
- "to": [
- "Pixel Axis 0_0"
- ],
- "pix2world": false,
- "coords": "Coordinates"
- },
- "b": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "b"
- },
- "Component_2": {
- "units": null,
- "_type": "glue.core.data.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoBAAAAAAAAAAIAAAAAAAAAAwAAAAAAAAA="
- }
- },
- "Component_1": {
- "units": null,
- "_type": "glue.core.data.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoBAAAAAAAAAAIAAAAAAAAAAwAAAAAAAAA="
- }
- },
- "Component_0": {
- "units": null,
- "_type": "glue.core.data.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoBAAAAAAAAAAIAAAAAAAAAAwAAAAAAAAA="
- }
- },
- "t2": {
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "color": "#373737",
- "markersize": 3,
- "marker": "o",
- "alpha": 0.5,
- "linewidth": 1,
- "linestyle": "solid"
- },
- "_protocol": 3,
- "subsets": [],
- "_type": "glue.core.data.Data",
- "label": "t2",
- "coords": "Coordinates_0",
- "components": [
- [
- "b",
- "Component"
- ],
- [
- "Pixel Axis 0",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "l",
- "Component_0"
- ],
- [
- "ra",
- "DerivedComponent"
- ],
- [
- "dec",
- "DerivedComponent_0"
- ]
- ],
- "_key_joins": []
- },
- "l": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "l"
- },
- "t1": {
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "color": "#373737",
- "markersize": 3,
- "marker": "o",
- "alpha": 0.5,
- "linewidth": 1,
- "linestyle": "solid"
- },
- "_protocol": 3,
- "subsets": [],
- "_type": "glue.core.data.Data",
- "label": "t1",
- "coords": "Coordinates",
- "components": [
- [
- "dec",
- "Component_1"
- ],
- [
- "Pixel Axis 0_0",
- "CoordinateComponent_1"
- ],
- [
- "World 0_0",
- "CoordinateComponent_2"
- ],
- [
- "ra",
- "Component_2"
- ],
- [
- "l",
- "DerivedComponent_1"
- ],
- [
- "b",
- "DerivedComponent_2"
- ]
- ],
- "_key_joins": []
- },
- "DataCollection": {
- "_type": "glue.core.data_collection.DataCollection",
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component_0",
- "DerivedComponent",
- "DerivedComponent_0",
- "Component_1",
- "CoordinateComponent_1",
- "CoordinateComponent_2",
- "Component_2",
- "DerivedComponent_1",
- "DerivedComponent_2"
- ],
- "links": [
- "ComponentLink",
- "ComponentLink_0",
- "ComponentLink_1",
- "CoordinateComponentLink",
- "ComponentLink_2",
- "CoordinateComponentLink_0",
- "ComponentLink_3",
- "ComponentLink_4",
- "ComponentLink_5",
- "CoordinateComponentLink_1",
- "ComponentLink_6",
- "CoordinateComponentLink_2"
- ],
- "_protocol": 2,
- "groups": [],
- "cids": [
- "b",
- "Pixel Axis 0",
- "World 0",
- "l",
- "ra",
- "dec",
- "dec",
- "Pixel Axis 0_0",
- "World 0_0",
- "ra",
- "l",
- "b"
- ],
- "data": [
- "t2",
- "t1"
- ]
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "dec": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "dec"
- },
- "ComponentLink_0": {
- "_type": "glue.core.component_link.ComponentLink",
- "inverse": null,
- "frm": [
- "ra",
- "dec"
- ],
- "to": [
- "l"
- ],
- "using": {
- "function": "glue.core.link_helpers.radec2glon",
- "_type": "types.FunctionType"
- },
- "hidden": false
- }
-}
\ No newline at end of file
diff --git a/glue/tests/data/simple.csv b/glue/tests/data/simple.csv
deleted file mode 100644
index fa0e8a7a0..000000000
--- a/glue/tests/data/simple.csv
+++ /dev/null
@@ -1,4 +0,0 @@
-a,b
-1,2
-3,2
-5,3
diff --git a/glue/tests/data/simple_hdf5_grid.glu b/glue/tests/data/simple_hdf5_grid.glu
deleted file mode 100644
index 9fbacf9fd..000000000
--- a/glue/tests/data/simple_hdf5_grid.glu
+++ /dev/null
@@ -1,498 +0,0 @@
-{
- "CoordinateComponent_9": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 1
- },
- "CoordinateComponent_8": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "World 0_0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 0"
- },
- "World 2": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 2"
- },
- "World 1": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 1"
- },
- "CoordinateComponent_0": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 1
- },
- "single_grid": {
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "color": "#373737",
- "markersize": 3,
- "marker": "o",
- "alpha": 0.5,
- "linewidth": 1,
- "linestyle": "solid"
- },
- "_protocol": 3,
- "subsets": [],
- "_type": "glue.core.data.Data",
- "label": "single_grid",
- "coords": "Coordinates",
- "components": [
- [
- "/array1_0",
- "Component_0"
- ],
- [
- "Pixel z_0",
- "CoordinateComponent_5"
- ],
- [
- "Pixel y_0",
- "CoordinateComponent_6"
- ],
- [
- "Pixel x_0",
- "CoordinateComponent_7"
- ],
- [
- "World 0_0",
- "CoordinateComponent_8"
- ],
- [
- "World 1_0",
- "CoordinateComponent_9"
- ],
- [
- "World 2_0",
- "CoordinateComponent_10"
- ]
- ],
- "_key_joins": []
- },
- "CoordinateComponent_6": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 1
- },
- "CoordinateComponent_5": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "CoordinateComponent_4": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 2
- },
- "World 1_0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 1"
- },
- "CoordinateComponentLink_6": {
- "index": 2,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0",
- "World 1",
- "World 2"
- ],
- "to": [
- "Pixel x"
- ],
- "pix2world": false,
- "coords": "Coordinates_0"
- },
- "CoordinateComponentLink_10": {
- "index": 2,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0_0",
- "World 1_0",
- "World 2_0"
- ],
- "to": [
- "Pixel x_0"
- ],
- "pix2world": false,
- "coords": "Coordinates"
- },
- "__main__": {
- "_type": "glue.qt.glue_application.GlueApplication",
- "session": "Session",
- "data": "DataCollection",
- "viewers": [
- []
- ]
- },
- "CoordinateComponentLink_2": {
- "index": 1,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0",
- "World 1",
- "World 2"
- ],
- "to": [
- "Pixel y"
- ],
- "pix2world": false,
- "coords": "Coordinates_0"
- },
- "Pixel x_0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel x"
- },
- "World 2_0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 2"
- },
- "Component": {
- "log_item": 0,
- "_type": "glue.core.data.Component",
- "log": "LoadLog"
- },
- "Pixel y_0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel y"
- },
- "CoordinateComponent_3": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 1
- },
- "Pixel z_0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel z"
- },
- "CoordinateComponentLink": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0",
- "World 1",
- "World 2"
- ],
- "to": [
- "Pixel z"
- ],
- "pix2world": false,
- "coords": "Coordinates_0"
- },
- "/array1_0": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "/array1"
- },
- "CoordinateComponent_2": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "CoordinateComponent_10": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 2
- },
- "CoordinateComponent_1": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 2
- },
- "CoordinateComponentLink_9": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel z",
- "Pixel y",
- "Pixel x"
- ],
- "to": [
- "World 0"
- ],
- "pix2world": true,
- "coords": "Coordinates_0"
- },
- "World 0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 0"
- },
- "Pixel z": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel z"
- },
- "Pixel y": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel y"
- },
- "Pixel x": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel x"
- },
- "CoordinateComponentLink_3": {
- "index": 2,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel z_0",
- "Pixel y_0",
- "Pixel x_0"
- ],
- "to": [
- "World 2_0"
- ],
- "pix2world": true,
- "coords": "Coordinates"
- },
- "CoordinateComponent_7": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 2
- },
- "CoordinateComponentLink_1": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0_0",
- "World 1_0",
- "World 2_0"
- ],
- "to": [
- "Pixel z_0"
- ],
- "pix2world": false,
- "coords": "Coordinates"
- },
- "CoordinateComponentLink_0": {
- "index": 1,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel z",
- "Pixel y",
- "Pixel x"
- ],
- "to": [
- "World 1"
- ],
- "pix2world": true,
- "coords": "Coordinates_0"
- },
- "CoordinateComponentLink_7": {
- "index": 1,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel z_0",
- "Pixel y_0",
- "Pixel x_0"
- ],
- "to": [
- "World 1_0"
- ],
- "pix2world": true,
- "coords": "Coordinates"
- },
- "LoadLog": {
- "path": "{DATA_PATH}single_grid.hdf5",
- "_type": "glue.core.data_factories.LoadLog",
- "factory": {
- "function": "glue.core.data_factories.auto_data",
- "_type": "types.FunctionType"
- },
- "kwargs": [
- []
- ]
- },
- "CoordinateComponentLink_5": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel z_0",
- "Pixel y_0",
- "Pixel x_0"
- ],
- "to": [
- "World 0_0"
- ],
- "pix2world": true,
- "coords": "Coordinates"
- },
- "Coordinates_0": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "CoordinateComponent": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "CoordinateComponentLink_4": {
- "index": 2,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel z",
- "Pixel y",
- "Pixel x"
- ],
- "to": [
- "World 2"
- ],
- "pix2world": true,
- "coords": "Coordinates_0"
- },
- "CoordinateComponentLink_8": {
- "index": 1,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0_0",
- "World 1_0",
- "World 2_0"
- ],
- "to": [
- "Pixel y_0"
- ],
- "pix2world": false,
- "coords": "Coordinates"
- },
- "/array1": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "/array1"
- },
- "Component_0": {
- "log_item": 0,
- "_type": "glue.core.data.Component",
- "log": "LoadLog_0"
- },
- "DataCollection": {
- "_type": "glue.core.data_collection.DataCollection",
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "CoordinateComponent_1",
- "CoordinateComponent_2",
- "CoordinateComponent_3",
- "CoordinateComponent_4",
- "Component_0",
- "CoordinateComponent_5",
- "CoordinateComponent_6",
- "CoordinateComponent_7",
- "CoordinateComponent_8",
- "CoordinateComponent_9",
- "CoordinateComponent_10"
- ],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0",
- "CoordinateComponentLink_1",
- "CoordinateComponentLink_2",
- "CoordinateComponentLink_3",
- "CoordinateComponentLink_4",
- "CoordinateComponentLink_5",
- "CoordinateComponentLink_6",
- "CoordinateComponentLink_7",
- "CoordinateComponentLink_8",
- "CoordinateComponentLink_9",
- "CoordinateComponentLink_10"
- ],
- "_protocol": 2,
- "groups": [],
- "cids": [
- "/array1",
- "Pixel z",
- "Pixel y",
- "Pixel x",
- "World 0",
- "World 1",
- "World 2",
- "/array1_0",
- "Pixel z_0",
- "Pixel y_0",
- "Pixel x_0",
- "World 0_0",
- "World 1_0",
- "World 2_0"
- ],
- "data": [
- "single_grid_auto",
- "single_grid"
- ]
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "LoadLog_0": {
- "path": "{DATA_PATH}single_grid.hdf5",
- "_type": "glue.core.data_factories.LoadLog",
- "factory": {
- "function": "glue.core.data_factories.gridded_data",
- "_type": "types.FunctionType"
- },
- "kwargs": [
- []
- ]
- },
- "single_grid_auto": {
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "color": "#373737",
- "markersize": 3,
- "marker": "o",
- "alpha": 0.5019607843137255,
- "linewidth": 1,
- "linestyle": "solid"
- },
- "_protocol": 3,
- "subsets": [],
- "_type": "glue.core.data.Data",
- "label": "single_grid_auto",
- "coords": "Coordinates_0",
- "components": [
- [
- "/array1",
- "Component"
- ],
- [
- "Pixel z",
- "CoordinateComponent"
- ],
- [
- "Pixel y",
- "CoordinateComponent_0"
- ],
- [
- "Pixel x",
- "CoordinateComponent_1"
- ],
- [
- "World 0",
- "CoordinateComponent_2"
- ],
- [
- "World 1",
- "CoordinateComponent_3"
- ],
- [
- "World 2",
- "CoordinateComponent_4"
- ]
- ],
- "_key_joins": []
- }
-}
\ No newline at end of file
diff --git a/glue/tests/data/simple_table_015.glu b/glue/tests/data/simple_table_015.glu
deleted file mode 100644
index 0f731efd4..000000000
--- a/glue/tests/data/simple_table_015.glu
+++ /dev/null
@@ -1,152 +0,0 @@
-{
- "Component": {
- "_type": "glue.core.component.Component",
- "log": "LoadLog",
- "log_item": 2
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "log": "LoadLog",
- "log_item": 3
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 4,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "Pixel Axis 0 [x]",
- "World 0",
- "a",
- "b"
- ],
- "components": [
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component",
- "Component_0"
- ],
- "data": [
- "single_table[HDU1]"
- ],
- "groups": [],
- "links": [],
- "subset_group_count": 0
- },
- "LoadLog": {
- "_protocol": 1,
- "_type": "glue.core.data_factories.helpers.LoadLog",
- "factory": {
- "_type": "types.FunctionType",
- "function": "glue.core.data_factories.fits.fits_reader"
- },
- "kwargs": [
- []
- ],
- "path": "{DATA_PATH}/single_table.fits"
- },
- "Pixel Axis 0 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "label": "Pixel Axis 0 [x]"
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "World 0"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue.viewers.profile.qt",
- "glue.core.data_exporters",
- "glue.io.formats.fits",
- "glue.plugins.data_factories.spectral_cube",
- "glue.plugins.tools.pv_slicer",
- "glue.viewers.histogram.qt",
- "glue.plugins.coordinate_helpers",
- "glue.viewers.image.qt",
- "glue.plugins.export_d3po",
- "glue.plugins.tools",
- "glue.viewers.scatter.qt",
- "glue.plugins.wcs_autolinking",
- "glue.plugins.dendro_viewer.qt",
- "glue.viewers.table.qt"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- []
- ]
- },
- "a": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "a"
- },
- "b": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "b"
- },
- "single_table[HDU1]": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "Pixel Axis 0 [x]",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "a",
- "Component"
- ],
- [
- "b",
- "Component_0"
- ]
- ],
- "coords": "Coordinates",
- "label": "single_table[HDU1]",
- "meta": {
- "_type": "collections.OrderedDict",
- "contents": {}
- },
- "primary_owner": [
- "Pixel Axis 0 [x]",
- "World 0",
- "a",
- "b"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "#595959",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [],
- "uuid": "d804c55e-ebee-4850-a0f1-3b854bda62b4"
- }
-}
diff --git a/glue/tests/data/simple_table_resaved.glu b/glue/tests/data/simple_table_resaved.glu
deleted file mode 100644
index b39b2344d..000000000
--- a/glue/tests/data/simple_table_resaved.glu
+++ /dev/null
@@ -1,152 +0,0 @@
-{
- "Component": {
- "_type": "glue.core.component.Component",
- "log": "LoadLog",
- "log_item": 2
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "log": "LoadLog",
- "log_item": 3
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 4,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "Pixel Axis 0 [x]",
- "World 0",
- "a",
- "b"
- ],
- "components": [
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component",
- "Component_0"
- ],
- "data": [
- "single_table[HDU1]"
- ],
- "groups": [],
- "links": [],
- "subset_group_count": 0
- },
- "LoadLog": {
- "_protocol": 2,
- "_type": "glue.core.data_factories.helpers.LoadLog",
- "factory": {
- "_type": "types.FunctionType",
- "function": "glue.core.data_factories.fits.fits_reader"
- },
- "kwargs": [
- []
- ],
- "path": "{DATA_PATH}/single_table.fits"
- },
- "Pixel Axis 0 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "label": "Pixel Axis 0 [x]"
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "World 0"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue.viewers.scatter.qt",
- "glue.plugins.data_factories.spectral_cube",
- "glue.core.data_exporters",
- "glue.viewers.image.qt",
- "glue.plugins.coordinate_helpers",
- "glue.plugins.tools",
- "glue.viewers.table.qt",
- "glue.plugins.dendro_viewer.qt",
- "glue.viewers.histogram.qt",
- "glue.plugins.wcs_autolinking",
- "glue.io.formats.fits",
- "glue.plugins.tools.pv_slicer",
- "glue.plugins.export_d3po",
- "glue.viewers.profile.qt"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- []
- ]
- },
- "a": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "a"
- },
- "b": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "b"
- },
- "single_table[HDU1]": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "Pixel Axis 0 [x]",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "a",
- "Component"
- ],
- [
- "b",
- "Component_0"
- ]
- ],
- "coords": "Coordinates",
- "label": "single_table[HDU1]",
- "meta": {
- "_type": "collections.OrderedDict",
- "contents": {}
- },
- "primary_owner": [
- "Pixel Axis 0 [x]",
- "World 0",
- "a",
- "b"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "#595959",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [],
- "uuid": "d804c55e-ebee-4850-a0f1-3b854bda62b4"
- }
-}
diff --git a/glue/tests/data/simple_tables.glu b/glue/tests/data/simple_tables.glu
deleted file mode 100644
index 7775bcc64..000000000
--- a/glue/tests/data/simple_tables.glu
+++ /dev/null
@@ -1,522 +0,0 @@
-{
- "LoadLog": {
- "path": "{DATA_PATH}single_table.fits",
- "_type": "glue.core.data_factories.LoadLog",
- "factory": {
- "function": "glue.core.data_factories.auto_data",
- "_type": "types.FunctionType"
- },
- "kwargs": [
- []
- ]
- },
- "a_2": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "a"
- },
- "a_1": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "a"
- },
- "a_0": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "a"
- },
- "World 0_0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 0"
- },
- "World 0_1": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 0"
- },
- "World 0_2": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 0"
- },
- "World 0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 0"
- },
- "Coordinates_1": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "CoordinateComponent_6": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "CoordinateComponent_5": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "CoordinateComponent_4": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "__main__": {
- "_type": "glue.qt.glue_application.GlueApplication",
- "session": "Session",
- "data": "DataCollection",
- "viewers": [
- []
- ]
- },
- "b_0": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "b"
- },
- "b_1": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "b"
- },
- "b_2": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "b"
- },
- "double_tables": {
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "color": "#373737",
- "markersize": 3,
- "marker": "o",
- "alpha": 0.5,
- "linewidth": 1,
- "linestyle": "solid"
- },
- "_protocol": 3,
- "subsets": [],
- "_type": "glue.core.data.Data",
- "label": "double_tables",
- "coords": "Coordinates",
- "components": [
- [
- "a_2",
- "Component_5"
- ],
- [
- "Pixel Axis 0_2",
- "CoordinateComponent_5"
- ],
- [
- "World 0_2",
- "CoordinateComponent_6"
- ],
- [
- "b_2",
- "Component_6"
- ]
- ],
- "_key_joins": []
- },
- "Component": {
- "log_item": 0,
- "_type": "glue.core.data.Component",
- "log": "LoadLog"
- },
- "single_table": {
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "color": "#373737",
- "markersize": 3,
- "marker": "o",
- "alpha": 0.5,
- "linewidth": 1,
- "linestyle": "solid"
- },
- "_protocol": 3,
- "subsets": [],
- "_type": "glue.core.data.Data",
- "label": "single_table",
- "coords": "Coordinates_0",
- "components": [
- [
- "a_0",
- "Component_1"
- ],
- [
- "Pixel Axis 0_0",
- "CoordinateComponent_1"
- ],
- [
- "World 0_0",
- "CoordinateComponent_2"
- ],
- [
- "b_0",
- "Component_2"
- ]
- ],
- "_key_joins": []
- },
- "CoordinateComponent_3": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "CoordinateComponentLink": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0_2"
- ],
- "to": [
- "Pixel Axis 0_2"
- ],
- "pix2world": false,
- "coords": "Coordinates"
- },
- "CoordinateComponent_2": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "CoordinateComponent_1": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "single_table_auto": {
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "color": "#373737",
- "markersize": 3,
- "marker": "o",
- "alpha": 0.5019607843137255,
- "linewidth": 1,
- "linestyle": "solid"
- },
- "_protocol": 3,
- "subsets": [],
- "_type": "glue.core.data.Data",
- "label": "single_table_auto",
- "coords": "Coordinates_1",
- "components": [
- [
- "a",
- "Component"
- ],
- [
- "Pixel Axis 0",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "b",
- "Component_0"
- ]
- ],
- "_key_joins": []
- },
- "CoordinateComponent_0": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "Pixel Axis 0_0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel Axis 0"
- },
- "Pixel Axis 0_1": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel Axis 0"
- },
- "Pixel Axis 0_2": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel Axis 0"
- },
- "Pixel Axis 0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel Axis 0"
- },
- "CoordinateComponentLink_3": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0"
- ],
- "to": [
- "Pixel Axis 0"
- ],
- "pix2world": false,
- "coords": "Coordinates_1"
- },
- "CoordinateComponentLink_2": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel Axis 0"
- ],
- "to": [
- "World 0"
- ],
- "pix2world": true,
- "coords": "Coordinates_1"
- },
- "CoordinateComponentLink_1": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel Axis 0_0"
- ],
- "to": [
- "World 0_0"
- ],
- "pix2world": true,
- "coords": "Coordinates_0"
- },
- "CoordinateComponentLink_0": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel Axis 0_1"
- ],
- "to": [
- "World 0_1"
- ],
- "pix2world": true,
- "coords": "Coordinates_2"
- },
- "CoordinateComponentLink_6": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0_1"
- ],
- "to": [
- "Pixel Axis 0_1"
- ],
- "pix2world": false,
- "coords": "Coordinates_2"
- },
- "CoordinateComponentLink_5": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0_0"
- ],
- "to": [
- "Pixel Axis 0_0"
- ],
- "pix2world": false,
- "coords": "Coordinates_0"
- },
- "Coordinates_0": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "Coordinates_2": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "CoordinateComponent": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "CoordinateComponentLink_4": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel Axis 0_2"
- ],
- "to": [
- "World 0_2"
- ],
- "pix2world": true,
- "coords": "Coordinates"
- },
- "a": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "a"
- },
- "b": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "b"
- },
- "double_tables_auto": {
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "color": "#373737",
- "markersize": 3,
- "marker": "o",
- "alpha": 0.5019607843137255,
- "linewidth": 1,
- "linestyle": "solid"
- },
- "_protocol": 3,
- "subsets": [],
- "_type": "glue.core.data.Data",
- "label": "double_tables_auto",
- "coords": "Coordinates_2",
- "components": [
- [
- "a_1",
- "Component_3"
- ],
- [
- "Pixel Axis 0_1",
- "CoordinateComponent_3"
- ],
- [
- "World 0_1",
- "CoordinateComponent_4"
- ],
- [
- "b_1",
- "Component_4"
- ]
- ],
- "_key_joins": []
- },
- "Component_3": {
- "log_item": 0,
- "_type": "glue.core.data.Component",
- "log": "LoadLog_0"
- },
- "Component_2": {
- "log_item": 3,
- "_type": "glue.core.data.Component",
- "log": "LoadLog_1"
- },
- "Component_1": {
- "log_item": 0,
- "_type": "glue.core.data.Component",
- "log": "LoadLog_1"
- },
- "Component_0": {
- "log_item": 3,
- "_type": "glue.core.data.Component",
- "log": "LoadLog"
- },
- "Component_6": {
- "log_item": 3,
- "_type": "glue.core.data.Component",
- "log": "LoadLog_2"
- },
- "Component_5": {
- "log_item": 0,
- "_type": "glue.core.data.Component",
- "log": "LoadLog_2"
- },
- "Component_4": {
- "log_item": 3,
- "_type": "glue.core.data.Component",
- "log": "LoadLog_0"
- },
- "DataCollection": {
- "_type": "glue.core.data_collection.DataCollection",
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component_0",
- "Component_1",
- "CoordinateComponent_1",
- "CoordinateComponent_2",
- "Component_2",
- "Component_3",
- "CoordinateComponent_3",
- "CoordinateComponent_4",
- "Component_4",
- "Component_5",
- "CoordinateComponent_5",
- "CoordinateComponent_6",
- "Component_6"
- ],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0",
- "CoordinateComponentLink_1",
- "CoordinateComponentLink_2",
- "CoordinateComponentLink_3",
- "CoordinateComponentLink_4",
- "CoordinateComponentLink_5",
- "CoordinateComponentLink_6"
- ],
- "_protocol": 2,
- "groups": [],
- "cids": [
- "a",
- "Pixel Axis 0",
- "World 0",
- "b",
- "a_0",
- "Pixel Axis 0_0",
- "World 0_0",
- "b_0",
- "a_1",
- "Pixel Axis 0_1",
- "World 0_1",
- "b_1",
- "a_2",
- "Pixel Axis 0_2",
- "World 0_2",
- "b_2"
- ],
- "data": [
- "single_table_auto",
- "single_table",
- "double_tables_auto",
- "double_tables"
- ]
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "LoadLog_2": {
- "path": "{DATA_PATH}double_tables.fits",
- "_type": "glue.core.data_factories.LoadLog",
- "factory": {
- "function": "glue.core.data_factories.astropy_tabular_data",
- "_type": "types.FunctionType"
- },
- "kwargs": [
- []
- ]
- },
- "LoadLog_0": {
- "path": "{DATA_PATH}double_tables.fits",
- "_type": "glue.core.data_factories.LoadLog",
- "factory": {
- "function": "glue.core.data_factories.auto_data",
- "_type": "types.FunctionType"
- },
- "kwargs": [
- []
- ]
- },
- "LoadLog_1": {
- "path": "{DATA_PATH}single_table.fits",
- "_type": "glue.core.data_factories.LoadLog",
- "factory": {
- "function": "glue.core.data_factories.astropy_tabular_data",
- "_type": "types.FunctionType"
- },
- "kwargs": [
- []
- ]
- }
-}
\ No newline at end of file
diff --git a/glue/tests/data/simple_viewers.glu b/glue/tests/data/simple_viewers.glu
deleted file mode 100644
index 88cea9d7b..000000000
--- a/glue/tests/data/simple_viewers.glu
+++ /dev/null
@@ -1,429 +0,0 @@
-{
- "ScatterWidget": {
- "layers": [
- {
- "_type": "glue.clients.layer_artist.ScatterLayerArtist",
- "layer": "table",
- "yatt": "a",
- "visible": true,
- "zorder": 1,
- "xatt": "b"
- }
- ],
- "_type": "glue.qt.widgets.scatter_widget.ScatterWidget",
- "pos": [
- 0,
- 0
- ],
- "session": "Session",
- "properties": {
- "xflip": false,
- "ymax": 3.04,
- "xlog": true,
- "yflip": true,
- "yatt": "a",
- "ylog": false,
- "xmax": 4.36,
- "xmin": 1.24,
- "hidden": false,
- "ymin": 0.96,
- "xatt": "b"
- },
- "size": [
- 670,
- 512
- ]
- },
- "World 0_0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 0"
- },
- "CoordinateComponent_2": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 1
- },
- "image": {
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "color": "#373737",
- "markersize": 3,
- "marker": "o",
- "alpha": 0.5,
- "linewidth": 1,
- "linestyle": "solid"
- },
- "_protocol": 3,
- "subsets": [],
- "_type": "glue.core.data.Data",
- "label": "image",
- "coords": "Coordinates",
- "components": [
- [
- "image_0",
- "Component_1"
- ],
- [
- "Pixel y",
- "CoordinateComponent_1"
- ],
- [
- "Pixel x",
- "CoordinateComponent_2"
- ],
- [
- "World 0_0",
- "CoordinateComponent_3"
- ],
- [
- "World 1",
- "CoordinateComponent_4"
- ]
- ],
- "_key_joins": []
- },
- "World 0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 0"
- },
- "Coordinates_0": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "CoordinateComponent_4": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 1
- },
- "__main__": {
- "_type": "glue.qt.glue_application.GlueApplication",
- "session": "Session",
- "data": "DataCollection",
- "viewers": [
- [
- "ScatterWidget",
- "ImageWidget",
- "HistogramWidget"
- ]
- ]
- },
- "table": {
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "color": "#373737",
- "markersize": 3,
- "marker": "o",
- "alpha": 0.5,
- "linewidth": 1,
- "linestyle": "solid"
- },
- "_protocol": 3,
- "subsets": [],
- "_type": "glue.core.data.Data",
- "label": "table",
- "coords": "Coordinates_0",
- "components": [
- [
- "a",
- "Component"
- ],
- [
- "Pixel Axis 0",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "b",
- "Component_0"
- ]
- ],
- "_key_joins": []
- },
- "image_0": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "image"
- },
- "CoordinateComponent": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "Pixel x": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel x"
- },
- "Component": {
- "units": null,
- "_type": "glue.core.data.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoBAAAAAAAAAAIAAAAAAAAAAwAAAAAAAAA="
- }
- },
- "CoordinateComponent_3": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "ImageWidget": {
- "layers": [
- {
- "visible": true,
- "layer": "image",
- "zorder": 1,
- "_type": "glue.clients.layer_artist.ImageLayerArtist",
- "norm": "DS9Normalize"
- }
- ],
- "_type": "glue.qt.widgets.image_widget.ImageWidget",
- "pos": [
- 672,
- 0
- ],
- "session": "Session",
- "properties": {
- "rgb_viz": [
- true,
- true,
- true
- ],
- "ratt": null,
- "rgb_mode": false,
- "gatt": null,
- "attribute": "image_0",
- "batt": null,
- "slice": [
- "y",
- "x"
- ],
- "data": "image"
- },
- "size": [
- 562,
- 513
- ]
- },
- "CoordinateComponentLink": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0_0",
- "World 1"
- ],
- "to": [
- "Pixel y"
- ],
- "pix2world": false,
- "coords": "Coordinates"
- },
- "World 1": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "World 1"
- },
- "CoordinateComponent_0": {
- "world": true,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "HistogramWidget": {
- "layers": [
- {
- "nbins": 5.0,
- "layer": "table",
- "lo": 1.3,
- "xlog": false,
- "_type": "glue.clients.layer_artist.HistogramLayerArtist",
- "visible": true,
- "hi": 4.2999999999999998,
- "zorder": 1
- }
- ],
- "_type": "glue.qt.widgets.histogram_widget.HistogramWidget",
- "pos": [
- 0,
- 535
- ],
- "session": "Session",
- "properties": {
- "nbins": 5.0,
- "normed": false,
- "autoscale": true,
- "xlog": false,
- "cumulative": false,
- "component": "b",
- "ylog": false,
- "xmax": 4.3,
- "xmin": 1.3
- },
- "size": [
- 1235,
- 531
- ]
- },
- "Pixel y": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel y"
- },
- "Pixel Axis 0": {
- "hidden": true,
- "_type": "glue.core.data.ComponentID",
- "label": "Pixel Axis 0"
- },
- "CoordinateComponentLink_3": {
- "index": 1,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel y",
- "Pixel x"
- ],
- "to": [
- "World 1"
- ],
- "pix2world": true,
- "coords": "Coordinates"
- },
- "CoordinateComponentLink_2": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0"
- ],
- "to": [
- "Pixel Axis 0"
- ],
- "pix2world": false,
- "coords": "Coordinates_0"
- },
- "CoordinateComponentLink_1": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel y",
- "Pixel x"
- ],
- "to": [
- "World 0_0"
- ],
- "pix2world": true,
- "coords": "Coordinates"
- },
- "CoordinateComponentLink_0": {
- "index": 0,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "Pixel Axis 0"
- ],
- "to": [
- "World 0"
- ],
- "pix2world": true,
- "coords": "Coordinates_0"
- },
- "CoordinateComponentLink_4": {
- "index": 1,
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "frm": [
- "World 0_0",
- "World 1"
- ],
- "to": [
- "Pixel x"
- ],
- "pix2world": false,
- "coords": "Coordinates"
- },
- "a": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "a"
- },
- "b": {
- "hidden": false,
- "_type": "glue.core.data.ComponentID",
- "label": "b"
- },
- "CoordinateComponent_1": {
- "world": false,
- "_type": "glue.core.data.CoordinateComponent",
- "axis": 0
- },
- "Component_1": {
- "units": null,
- "_type": "glue.core.data.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGY4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsIDMpLCB9ICAgICAgICAgIAooXatr9N7uP2BEXHn4oZo/A7ENS98v7D9I5JtTwmHEP3ajNj9M198/ZE5h+Z+Nzz9wEO/ZkuqlP94MlPisMuQ/G94dgwMP6j8="
- }
- },
- "Component_0": {
- "units": null,
- "_type": "glue.core.data.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGY4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIArNzMzMzMz0P83MzMzMzARAMzMzMzMzEUA="
- }
- },
- "DS9Normalize": {
- "vmax": 0.93116720658359486,
- "_type": "glue.clients.ds9norm.DS9Normalize",
- "bias": 0.5,
- "vmin": 0.032727208219196571,
- "clip_hi": 95.0,
- "stretch": "arcsinh",
- "clip_lo": 5.0,
- "contrast": 1.0
- },
- "DataCollection": {
- "_type": "glue.core.data_collection.DataCollection",
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component_0",
- "Component_1",
- "CoordinateComponent_1",
- "CoordinateComponent_2",
- "CoordinateComponent_3",
- "CoordinateComponent_4"
- ],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0",
- "CoordinateComponentLink_1",
- "CoordinateComponentLink_2",
- "CoordinateComponentLink_3",
- "CoordinateComponentLink_4"
- ],
- "_protocol": 2,
- "groups": [],
- "cids": [
- "a",
- "Pixel Axis 0",
- "World 0",
- "b",
- "image_0",
- "Pixel y",
- "Pixel x",
- "World 0_0",
- "World 1"
- ],
- "data": [
- "table",
- "image"
- ]
- },
- "Session": {
- "_type": "glue.core.session.Session"
- }
-}
\ No newline at end of file
diff --git a/glue/tests/data/single_grid.hdf5 b/glue/tests/data/single_grid.hdf5
deleted file mode 100644
index 4914eccf7..000000000
Binary files a/glue/tests/data/single_grid.hdf5 and /dev/null differ
diff --git a/glue/tests/data/single_table.fits b/glue/tests/data/single_table.fits
deleted file mode 100644
index f4f08f352..000000000
Binary files a/glue/tests/data/single_table.fits and /dev/null differ
diff --git a/glue/tests/helpers.py b/glue/tests/helpers.py
index db26cb393..5928cc646 100644
--- a/glue/tests/helpers.py
+++ b/glue/tests/helpers.py
@@ -15,6 +15,9 @@ def make_marker(mark_creator, module, label=None, version=None, mark_if='lt'):
if label == 'PyQt5': # PyQt5 does not use __version__
from PyQt5 import QtCore
version_installed = QtCore.PYQT_VERSION_STR
+ elif label == 'PyQt6': # PyQt6 does not use __version__
+ from PyQt6 import QtCore
+ version_installed = QtCore.PYQT_VERSION_STR
else:
mod = __import__(module)
version_installed = mod.__version__
@@ -73,11 +76,13 @@ def mark_creator(installed, lbl, vrs):
H5PY_INSTALLED, requires_h5py = make_skipper('h5py')
PYQT5_INSTALLED, requires_pyqt5 = make_skipper('PyQt5')
+PYQT6_INSTALLED, requires_pyqt6 = make_skipper('PyQt6')
PYSIDE2_INSTALLED, requires_pyside2 = make_skipper('PySide2')
+PYSIDE6_INSTALLED, requires_pyside6 = make_skipper('PySide6')
HYPOTHESIS_INSTALLED, requires_hypothesis = make_skipper('hypothesis')
-QT_INSTALLED = PYQT5_INSTALLED or PYSIDE2_INSTALLED
+QT_INSTALLED = PYQT5_INSTALLED or PYQT6_INSTALLED or PYSIDE2_INSTALLED or PYSIDE6_INSTALLED
SPECTRAL_CUBE_INSTALLED, requires_spectral_cube = make_skipper('spectral_cube',
label='spectral-cube')
diff --git a/glue/tests/test_config.py b/glue/tests/test_config.py
index 3d97772a4..a77133b67 100644
--- a/glue/tests/test_config.py
+++ b/glue/tests/test_config.py
@@ -1,25 +1,4 @@
-from ..config import qt_client, link_function, data_factory
-from glue.tests.helpers import requires_qt
-
-
-@requires_qt
-def test_default_clients():
-
- from glue.viewers.image.qt import ImageViewer
- from glue.viewers.scatter.qt import ScatterViewer
- from glue.viewers.histogram.qt import HistogramViewer
-
- assert ImageViewer in qt_client
- assert ScatterViewer in qt_client
- assert HistogramViewer in qt_client
-
-
-def test_add_client():
- @qt_client
- class TestClient(object):
- pass
-
- assert TestClient in qt_client
+from ..config import link_function, data_factory
def test_add_link_default():
diff --git a/glue/tests/test_deps.py b/glue/tests/test_deps.py
deleted file mode 100644
index 10814bc02..000000000
--- a/glue/tests/test_deps.py
+++ /dev/null
@@ -1,67 +0,0 @@
-import sys
-from subprocess import check_call
-
-from glue.tests.helpers import requires_qt
-
-from .._deps import Dependency, categories
-
-
-class TestDependency(object):
-
- def test_installed(self):
- d = Dependency('math', 'the math module')
- assert d.installed
-
- def test_uninstalled(self):
- d = Dependency('asdfasdf', 'Non-existent module')
- assert not d.installed
-
- def test_installed_str(self):
- d = Dependency('math', 'info')
- assert str(d) == " math:\tINSTALLED (unknown version)"
-
- def test_noinstalled_str(self):
- d = Dependency('asdfasdf', 'info')
- assert str(d) == " asdfasdf:\tMISSING (info)"
-
- def test_failed_str(self):
- d = Dependency('asdfasdf', 'info')
- d.failed = True
- assert str(d) == " asdfasdf:\tFAILED (info)"
-
-
-@requires_qt
-def test_optional_dependency_not_imported():
- """
- Ensure that a GlueApplication instance can be created without
- importing any non-required dependency
- """
- optional_deps = categories[5:]
- deps = [dep.module for cateogry, deps in optional_deps for dep in deps]
-
- code = """
-class ImportDenier(object):
- __forbidden = set(%s)
-
- def find_module(self, mod_name, pth=None):
- if pth:
- return
- if mod_name in self.__forbidden:
- return self
-
- def load_module(self, mod_name):
- raise ImportError("Importing %%s" %% mod_name)
-
- def exec_module(self, mod_name):
- raise ImportError("Importing %%s" %% mod_name)
-
-import sys
-sys.meta_path.append(ImportDenier())
-
-from glue.app.qt import GlueApplication
-from glue.core import data_factories
-ga = GlueApplication()
-""" % deps
-
- cmd = [sys.executable, '-c', code]
- check_call(cmd)
diff --git a/glue/tests/test_main.py b/glue/tests/test_main.py
deleted file mode 100644
index 85d23b25d..000000000
--- a/glue/tests/test_main.py
+++ /dev/null
@@ -1,111 +0,0 @@
-import os
-import pytest
-from unittest.mock import patch
-
-from glue.tests.helpers import requires_qt
-
-from ..core import Data
-from ..main import load_data_files, main, start_glue
-
-
-def test_load_data_files():
- with patch('glue.core.data_factories.load_data') as ld:
- ld.return_value = Data()
- dc = load_data_files(['test.py'])
- assert len(dc) == 1
-
-
-def check_main(cmd, glue, config, data):
- """Pass command to main program, check for expected parsing"""
- with patch('glue.main.start_glue') as sg:
- main(cmd.split())
- args, kwargs = sg.call_args
- assert kwargs.get('datafiles', None) == data
- assert kwargs.get('gluefile', None) == glue
- assert kwargs.get('config', None) == config
-
-
-def check_exec(cmd, pyfile):
- """Assert that main correctly dispatches to execute_script"""
- with patch('glue.main.execute_script') as es:
- main(cmd.split())
- args, kwargs = es.call_args
- assert args[0] == pyfile
-
-
-def test_main_single_data():
- check_main('glueqt test.fits', None, None, ['test.fits'])
-
-
-def test_main_multi_data():
- check_main('glueqt test.fits t2.csv', None, None, ['test.fits', 't2.csv'])
-
-
-def test_main_config():
- check_main('glueqt -c config.py', None, 'config.py', None)
-
-
-def test_main_glu_arg():
- check_main('glueqt -g test.glu', 'test.glu', None, None)
-
-
-def test_main_auto_glu():
- check_main('glueqt test.glu', 'test.glu', None, None)
-
-
-def test_main_many_args():
- check_main('glueqt -c config.py data.fits d2.csv', None,
- 'config.py', ['data.fits', 'd2.csv'])
-
-
-def test_exec():
- check_exec('glueqt -x test.py', 'test.py')
-
-
-def test_auto_exec():
- check_exec('glueqt test.py', 'test.py')
-
-
-@requires_qt
-def test_exec_real(tmpdir):
- # Actually test the script execution functionlity
- filename = tmpdir.join('test.py').strpath
- with open(filename, 'w') as f:
- f.write('a = 1')
- with patch('qtpy.QtWidgets.QMessageBox') as qmb:
- with patch('sys.exit') as exit:
- main('glue -x {0}'.format(os.path.abspath(filename)).split())
- assert exit.called_once_with(0)
-
-
-@pytest.mark.parametrize(('cmd'), ['glueqt -g test.glu test.fits',
- 'glueqt -g test.py test.fits',
- 'glueqt -x test.py -g test.glu',
- 'glueqt -x test.py -c test.py',
- 'glueqt -x',
- 'glueqt -g',
- 'glueqt -c'])
-def test_invalid(cmd):
- with pytest.raises(SystemExit):
- main(cmd.split())
-
-
-@requires_qt
-@pytest.mark.parametrize(('glue', 'config', 'data'),
- [('test.glu', None, None),
- (None, 'test.py', None),
- (None, None, ['test.fits']),
- (None, None, ['a.fits', 'b.fits']),
- (None, 'test.py', ['a.fits'])])
-def test_start(glue, config, data):
- with patch('glue.config.load_configuration') as lc:
- with patch('glue.main.load_data_files') as ldf:
- with patch('glue.app.qt.GlueApplication') as ga:
-
- ldf.return_value = Data()
-
- start_glue(glue, config, data)
- if config:
- lc.assert_called_once_with(search_path=[config])
- if data:
- ldf.assert_called_once_with(data)
diff --git a/glue/tests/test_qglue.py b/glue/tests/test_qglue.py
deleted file mode 100644
index cb0e26810..000000000
--- a/glue/tests/test_qglue.py
+++ /dev/null
@@ -1,237 +0,0 @@
-import pytest
-import numpy as np
-import pandas as pd
-from unittest.mock import patch
-
-from .. import qglue
-from ..core import BaseCartesianData, Data
-from ..core.exceptions import IncompatibleAttribute
-from ..core.registry import Registry
-from .helpers import requires_astropy, requires_qt
-
-
-@requires_qt
-@requires_astropy
-class TestQGlue(object):
-
- def setup_method(self, method):
-
- from astropy.table import Table
- from astropy.io.fits import HDUList, ImageHDU
-
- Registry().clear()
-
- x = [1, 2, 3]
- y = [2, 3, 4]
-
- u = [10, 20, 30, 40]
- v = [20, 40, 60, 80]
-
- self.xy = {'x': x, 'y': y}
- self.dict_data = {'u': u, 'v': v}
- self.recarray_data = np.rec.array([(0, 1), (2, 3)],
- dtype=[(str('a'), int), (str('b'), int)])
- self.astropy_table = Table({'x': x, 'y': y})
- self.bad_data = {'x': x, 'u': u}
- self.hdulist = HDUList([ImageHDU(x, name='PRIMARY')])
-
- self.x = np.array(x)
- self.y = np.array(y)
- self.u = np.array(u)
- self.v = np.array(v)
-
- def check_setup(self, dc, expected):
- # assert that the assembled data collection returned
- # form qglue matches expected structure
-
- # test for expected data, components
- for data in dc:
- components = set(c.label for c in data.components)
- e = expected.pop(data.label)
- for component in e:
- assert component in components
- assert len(expected) == 0
-
- def test_qglue_starts_application(self):
- pandas_data = pd.DataFrame(self.xy)
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(data1=pandas_data)
- ga.assert_called_once()
-
- def test_single_pandas(self):
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(data1=self.xy)
- dc = ga.call_args[0][0]
- self.check_setup(dc, {'data1': ['x', 'y']})
-
- def test_single_pandas_nonstring_column(self):
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(data1=pd.DataFrame({1: [1, 2, 3]}))
- dc = ga.call_args[0][0]
- self.check_setup(dc, {'data1': ['1']})
-
- def test_single_numpy(self):
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(data1=np.array([1, 2, 3]))
- dc = ga.call_args[0][0]
- self.check_setup(dc, {'data1': ['data1']})
-
- def test_single_list(self):
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(data1=[1, 2, 3])
- dc = ga.call_args[0][0]
- self.check_setup(dc, {'data1': ['data1']})
-
- def test_single_dict(self):
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(data2=self.dict_data)
- dc = ga.call_args[0][0]
- self.check_setup(dc, {'data2': ['u', 'v']})
-
- def test_recarray(self):
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(data3=self.recarray_data)
- dc = ga.call_args[0][0]
- self.check_setup(dc, {'data3': ['a', 'b']})
-
- def test_astropy_table(self):
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(data4=self.astropy_table)
- dc = ga.call_args[0][0]
- self.check_setup(dc, {'data4': ['x', 'y']})
-
- def test_multi_data(self):
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(data1=self.dict_data, data2=self.xy)
- dc = ga.call_args[0][0]
- self.check_setup(dc, {'data1': ['u', 'v'],
- 'data2': ['x', 'y']})
-
- def test_hdulist(self):
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(data1=self.hdulist).data_collection
- dc = ga.call_args[0][0]
- self.check_setup(dc, {'data1': ['PRIMARY']})
-
- def test_glue_data(self):
- d = Data(x=[1, 2, 3])
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(x=d)
- dc = ga.call_args[0][0]
- assert d.label == 'x'
-
- def test_base_data(self):
-
- class CustomData(BaseCartesianData):
-
- def get_kind(self):
- pass
-
- def compute_histogram(self):
- pass
-
- def compute_statistic(self):
- pass
-
- def get_mask(self):
- pass
-
- @property
- def shape(self):
- return ()
-
- @property
- def main_components(self):
- return []
-
- d = CustomData()
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(x=d)
- dc = ga.call_args[0][0]
-
- assert dc[0] is d
-
- def test_simple_link(self):
- using = lambda x: x * 2
- links = [['data1.x', 'data2.u', using]]
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(data1=self.xy, data2=self.dict_data, links=links)
- dc = ga.call_args[0][0]
-
- links = [[['x'], 'u', using]]
- self.check_setup(dc, {'data1': ['x', 'y'],
- 'data2': ['u', 'v']})
-
- d = dc[0] if dc[0].label == 'data1' else dc[1]
- np.testing.assert_array_equal(d['x'], self.x)
- np.testing.assert_array_equal(d['u'], self.x * 2)
- d = dc[0] if dc[0].label == 'data2' else dc[1]
- with pytest.raises(IncompatibleAttribute) as exc:
- d['x']
-
- def test_multi_link(self):
-
- def forwards(x, y):
- return x * 2, y * 3
-
- def backwards(x, y):
- return x / 2, y / 3
-
- links = [[['Data1.x', 'Data1.y'],
- ['Data2.u', 'Data2.v'], forwards, backwards]]
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(Data1=self.xy, Data2=self.dict_data, links=links)
- dc = ga.call_args[0][0]
-
- self.check_setup(dc, {'Data1': ['x', 'y'],
- 'Data2': ['u', 'v']})
-
- for d in dc:
- if d.label == 'Data1':
- np.testing.assert_array_equal(d['x'], self.x)
- np.testing.assert_array_equal(d['y'], self.y)
- np.testing.assert_array_equal(d['u'], self.x * 2)
- np.testing.assert_array_equal(d['v'], self.y * 3)
- else:
- np.testing.assert_array_equal(d['x'], self.u / 2)
- np.testing.assert_array_equal(d['y'], self.v / 3)
- np.testing.assert_array_equal(d['u'], self.u)
- np.testing.assert_array_equal(d['v'], self.v)
-
- def test_implicit_identity_link(self):
- links = [('Data1.x', 'Data2.v'),
- ('Data1.y', 'Data2.u')]
- with patch('glue.app.qt.GlueApplication') as ga:
- qglue(Data1=self.xy, Data2=self.dict_data, links=links)
- dc = ga.call_args[0][0]
- # currently, identity links rename the second link to first,
- # so u/v disappear
- for d in dc:
- if d.label == 'Data1':
- np.testing.assert_array_equal(d['x'], self.x)
- np.testing.assert_array_equal(d['y'], self.y)
- else:
- np.testing.assert_array_equal(d['y'], self.u)
- np.testing.assert_array_equal(d['x'], self.v)
-
- def test_bad_link(self):
- forwards = lambda *args: args
- links = [(['Data1.a'], ['Data2.b'], forwards)]
- with pytest.raises(ValueError) as exc:
- qglue(Data1=self.xy, Data2=self.dict_data, links=links)
- assert exc.value.args[0] == "Invalid link (no component named Data1.a)"
-
- def test_bad_data_shape(self):
- with pytest.raises(ValueError) as exc:
- qglue(d=self.bad_data)
- assert exc.value.args[0].startswith("Invalid format for data 'd'")
-
- def test_bad_data_format(self):
- with pytest.raises(TypeError) as exc:
- qglue(d=5)
- assert exc.value.args[0].startswith("Invalid data description")
-
- def test_malformed_data_dict(self):
- with pytest.raises(ValueError) as exc:
- qglue(d={'x': 'bad'})
- assert exc.value.args[0].startswith("Invalid format for data 'd'")
diff --git a/glue/tests/test_session_back_compat.py b/glue/tests/test_session_back_compat.py
deleted file mode 100644
index 741577d0b..000000000
--- a/glue/tests/test_session_back_compat.py
+++ /dev/null
@@ -1,333 +0,0 @@
-# Make sure that session files can be read in a backward-compatible manner
-
-import os
-import pytest
-import numpy as np
-
-from glue.tests.helpers import requires_astropy, requires_h5py, requires_qt, PYSIDE2_INSTALLED # noqa
-from glue.core.component import CoordinateComponent, Component
-from glue.core.state import GlueUnSerializer
-from glue.core.component_id import PixelComponentID
-
-DATA = os.path.join(os.path.dirname(__file__), 'data')
-
-
-@requires_qt
-@requires_astropy
-def test_load_simple_tables_04():
-
- # This loads a session file made with Glue v0.4. In this session, we have
- # loaded four tables. The first two are from the same file, but one loaded
- # via the auto loader and the other via the Astropy FITS table loader. The
- # second two were loaded similarly to the first two, but the file contains
- # two HDUs this time. However, in Glue v0.4, only the first HDU was read so
- # we shouldn't have access to columns c and d in ``double_tables.fits``.
-
- with open(os.path.join(DATA, 'simple_tables.glu'), 'r') as f:
- template = f.read()
-
- content = template.replace('{DATA_PATH}', (DATA + os.sep).replace('\\', '\\\\'))
- state = GlueUnSerializer.loads(content)
-
- ga = state.object('__main__')
-
- dc = ga.session.data_collection
-
- # All tables should actually be the same because the FITS reader back at
- # 0.4 only read in the first HDU so the new reader is back-compatible
- # since it preserves HDU order.
-
- assert len(dc) == 4
-
- assert dc[0].label == 'single_table_auto'
- assert dc[1].label == 'single_table'
- assert dc[2].label == 'double_tables_auto'
- assert dc[3].label == 'double_tables'
-
- np.testing.assert_equal(dc[0]['a'], [1, 2, 3])
- np.testing.assert_equal(dc[0]['b'], [4, 5, 6])
- np.testing.assert_equal(dc[0]['a'], dc[1]['a'])
- np.testing.assert_equal(dc[0]['b'], dc[1]['b'])
- np.testing.assert_equal(dc[0]['a'], dc[2]['a'])
- np.testing.assert_equal(dc[0]['b'], dc[2]['b'])
- np.testing.assert_equal(dc[0]['a'], dc[3]['a'])
- np.testing.assert_equal(dc[0]['b'], dc[3]['b'])
-
- ga.close()
-
-
-@requires_qt
-@requires_h5py
-def test_load_hdf5_grids_04():
-
- # This loads a session file made with Glue v0.4. In this session, we have
- # loaded two gridded datasets from an HDF5 datafile: the first one loaded
- # via the auto loader and the other via the FITS/HDF5 loader.
-
- with open(os.path.join(DATA, 'simple_hdf5_grid.glu'), 'r') as f:
- template = f.read()
-
- content = template.replace('{DATA_PATH}', (DATA + os.sep).replace('\\', '\\\\'))
- state = GlueUnSerializer.loads(content)
-
- ga = state.object('__main__')
-
- dc = ga.session.data_collection
-
- assert len(dc) == 2
-
- assert dc[0].label == 'single_grid_auto'
- assert dc[1].label == 'single_grid'
-
- np.testing.assert_equal(dc[0]['/array1'], 1)
- np.testing.assert_equal(dc[0]['/array1'].shape, (2, 3, 4))
-
- ga.close()
-
-
-@requires_qt
-@requires_astropy
-def test_load_link_helpers_04():
-
- # This loads a session file made with Glue v0.4. In this session, we have
- # two tables, and we use all the celestial link functions that were present
- # in Glue v0.4. We now check that the paths are patched when loading the
- # session (since the functions have been moved to a deprecated location)
-
- with open(os.path.join(DATA, 'session_links.glu'), 'r') as f:
- content = f.read()
-
- state = GlueUnSerializer.loads(content)
-
- ga = state.object('__main__')
- ga.close()
-
-
-@requires_qt
-@requires_astropy
-@pytest.mark.skipif('PYSIDE2_INSTALLED')
-def test_load_viewers_04():
-
- # FIXME - for some reason this test with PySide2 causes a leftover reference
- # to GlueApplication and appears to be due to x_log being True in the
- # scatter plot. I suspect maybe there is some kind of circular reference
-
- # This loads a session file made with Glue v0.4. In this session, we have
- # three viewers: one scatter viewer, one image viewer, and one histogram
- # viewer.
-
- with open(os.path.join(DATA, 'simple_viewers.glu'), 'r') as f:
- content = f.read()
-
- state = GlueUnSerializer.loads(content)
-
- ga = state.object('__main__')
-
- assert len(ga.viewers[0]) == 3
- labels = sorted([x.LABEL for x in ga.viewers[0]])
-
- assert labels == ['1D Histogram', '2D Image', '2D Scatter']
-
- viewers = {}
- for x in ga.viewers[0]:
- viewers[x.LABEL] = x
-
- h = viewers['1D Histogram']
- assert h.viewer_size == (1235, 531)
- assert h.position == (0, 535)
- assert h.state.x_att.label == 'b'
-
- i = viewers['2D Image']
- assert i.viewer_size == (562, 513)
- assert i.position == (672, 0)
- assert i.state.layers[0].attribute.label == "image"
-
- s = viewers['2D Scatter']
- assert s.viewer_size == (670, 512)
- assert s.position == (0, 0)
- assert s.state.x_att.label == 'b'
- assert s.state.y_att.label == 'a'
- assert s.state.x_log
- assert not s.state.y_log
-
- ga.close()
-
-
-@requires_qt
-def test_load_pixel_components_07():
-
- # This loads a session file made with Glue v0.7. In 0.7 and before,
- # PixelComponentID did not exist, so we need to make sure that when loading
- # in such files, we transform the appropriate ComponentIDs to
- # PixelComponentIDs.
-
- with open(os.path.join(DATA, 'glue_v0.7_pixel_roi_selection.glu'), 'r') as f:
- content = f.read()
-
- state = GlueUnSerializer.loads(content)
-
- ga = state.object('__main__')
-
- assert isinstance(ga.data_collection[0].pixel_component_ids[0], PixelComponentID)
- assert isinstance(ga.data_collection[0].pixel_component_ids[1], PixelComponentID)
-
- ga.close()
-
-
-@requires_qt
-def test_table_widget_010():
-
- from glue.viewers.table.qt.tests.test_data_viewer import check_values_and_color
-
- # This loads a session file made with Glue v0.10 that includes a table
- # viewer. This is to make sure that loading table viewers from old files
- # will always be backward-compatible.
-
- with open(os.path.join(DATA, 'glue_v0.10_table.glu'), 'r') as f:
- state = GlueUnSerializer.load(f)
-
- ga = state.object('__main__')
-
- viewer = ga.viewers[0][0]
-
- data = {'x': [1, 2, 3],
- 'y': [4, 5, 6]}
-
- colors = ['#e31a1c', '#6d7326', None]
-
- check_values_and_color(viewer.model, data, colors)
-
- ga.close()
-
-
-@requires_qt
-@pytest.mark.parametrize('protocol', (0, 1))
-def test_load_log(protocol):
-
- # Prior to Glue v0.13, components were added to the data as: first
- # non-coordinate component, then coordinate components, then remaining non-
- # coordinate components. In Glue v0.13, this changed to be coordinate
- # components then non-coordinate components. The LoadLog functionality
- # relies on an absolute component index, so we need to be careful - if the
- # session file was created prior to Glue v0.13, we need to load the
- # components in the log using the old order. The load_log_1.glu file was
- # made with Glue v0.12.2, while the load_log_2.glu file was made with
- # Glue v0.13.
-
- with open(os.path.join(DATA, 'load_log_{0}.glu'.format(protocol)), 'r') as f:
- template = f.read()
-
- content = template.replace('{DATA_PATH}', (DATA + os.sep).replace('\\', '\\\\'))
- state = GlueUnSerializer.loads(content)
-
- ga = state.object('__main__')
-
- dc = ga.session.data_collection
-
- assert len(dc) == 1
-
- data = dc[0]
-
- assert data.label == 'simple'
-
- np.testing.assert_equal(data['Pixel Axis 0 [x]'], [0, 1, 2])
- np.testing.assert_equal(data['World 0'], [0, 1, 2])
- np.testing.assert_equal(data['a'], [1, 3, 5])
- np.testing.assert_equal(data['b'], [2, 2, 3])
-
- if protocol == 0:
- assert data.components == [data.id['a'], data.id['Pixel Axis 0 [x]'], data.id['World 0'], data.id['b']]
- else:
- assert data.components == [data.id['Pixel Axis 0 [x]'], data.id['World 0'], data.id['a'], data.id['b']]
-
- assert type(data.get_component('Pixel Axis 0 [x]')) == CoordinateComponent
- assert type(data.get_component('World 0')) == CoordinateComponent
- assert type(data.get_component('a')) == Component
- assert type(data.get_component('b')) == Component
-
- ga.close()
-
-
-@requires_qt
-@requires_astropy
-def test_load_coordinate_link_helpers_013():
-
- # This loads a session file made with Glue v0.13. In this session, we have
- # two tables, and we use all the celestial link functions that were present
- # in Glue v0.13. We now check that the paths are patched when loading the
- # session (since the functions have been moved to a deprecated location)
-
- with open(os.path.join(DATA, 'session_coordinate_links_013.glu'), 'r') as f:
- content = f.read()
-
- state = GlueUnSerializer.loads(content)
-
- ga = state.object('__main__')
-
- data1, data2 = ga.session.data_collection
-
- print(data1)
- print(data2)
-
- # Check that the links works
- data1[data2.id['x']]
- data1[data2.id['y']]
- data2[data1.id['x']]
- data2[data1.id['y']]
-
- ga.close()
-
-
-@requires_qt
-@requires_astropy
-def test_load_resave_coords(tmp_path):
-
- # This is a regression test for a bug that caused issues when creating a
- # session file with a dataset without any world coordinates (e.g. a table)
- # in glue 0.15, then loading and re-saving the session in glue 0.16. The
- # issue is that the glue 0.16 file will use LoadLog with protocol 2, but
- # since the file was originally created in glue 0.15, it will include a
- # fake world coordinate column. LoadLog with protocol 2 was incorrectly
- # assumed to never have these world coordinates.
-
- # Load in a file create with glue 0.15.* which includes a world component
- # even though Data.coords is the default identity transform
- with open(os.path.join(DATA, 'simple_table_015.glu'), 'r') as f:
- template = f.read()
-
- content = template.replace('{DATA_PATH}', (DATA + os.sep).replace('\\', '\\\\'))
- state = GlueUnSerializer.loads(content)
-
- ga = state.object('__main__')
- dc = ga.session.data_collection
- assert len(dc) == 1
- ga.save_session(tmp_path / 'test.glu')
- ga.close()
-
- with open(tmp_path / 'test.glu', 'r') as f:
- content = f.read()
-
- state = GlueUnSerializer.loads(content)
- ga = state.object('__main__')
- dc = ga.session.data_collection
- assert len(dc) == 1
- ga.close()
-
-
-@requires_qt
-@requires_astropy
-def test_load_resave_coords_intermediate(tmp_path):
-
- # Load in a file create with glue 0.15.* which includes a world component
- # even though Data.coords is the default identity transform
- with open(os.path.join(DATA, 'simple_table_resaved.glu'), 'r') as f:
- template = f.read()
-
- content = template.replace('{DATA_PATH}', (DATA + os.sep).replace('\\', '\\\\'))
- state = GlueUnSerializer.loads(content)
-
- ga = state.object('__main__')
- dc = ga.session.data_collection
- assert len(dc) == 1
- ga.save_session(tmp_path / 'test.glu')
- ga.close()
diff --git a/glue/utils/matplotlib.py b/glue/utils/matplotlib.py
index 0e6464dfb..6a9319701 100644
--- a/glue/utils/matplotlib.py
+++ b/glue/utils/matplotlib.py
@@ -13,29 +13,18 @@
# We avoid importing matplotlib up here otherwise Matplotlib and therefore Qt
# get imported as soon as glue.utils is imported.
-from glue.external.axescache import AxesCache
from glue.utils.misc import DeferredMethod
MATPLOTLIB_GE_30 = Version(__version__) >= Version('3')
MATPLOTLIB_GE_36 = Version(__version__) >= Version('3.6')
-__all__ = ['renderless_figure', 'all_artists', 'new_artists', 'remove_artists',
+__all__ = ['all_artists', 'new_artists', 'remove_artists',
'get_extent', 'view_cascade', 'fast_limits', 'defer_draw',
- 'color2rgb', 'point_contour', 'cache_axes',
+ 'color2rgb', 'point_contour',
'datetime64_to_mpl', 'mpl_to_datetime64', 'color2hex']
-def renderless_figure():
- # Matplotlib figure that skips the render step, for test speed
- from unittest.mock import MagicMock
- import matplotlib.pyplot as plt
- fig = plt.figure()
- fig.canvas.draw = MagicMock()
- plt.close('all')
- return fig
-
-
def all_artists(fig):
"""
Build a set of all Matplotlib artists in a Figure
@@ -334,31 +323,6 @@ def freeze_margins(axes, margins=[1, 1, 1, 1]):
axes.figure.canvas.mpl_connect('resize_event', axes.resizer.on_resize)
-def cache_axes(axes, toolbar):
- """
- Set up caching for an axes object.
-
- After this, cached renders will be used to quickly re-render an axes during
- window resizing or interactive pan/zooming.
-
- This function returns an AxesCache instance.
-
- Parameters
- ----------
- axes : :class:`matplotlib.axes.Axes`
- The axes to cache
- toolbar : :class:`glue.viewers.common.qt.toolbar.BasicToolbar`
- The toolbar managing the axes' canvas
- """
- canvas = axes.figure.canvas
- cache = AxesCache(axes)
- canvas.resize_begin.connect(cache.enable)
- canvas.resize_end.connect(cache.disable)
- toolbar.pan_begin.connect(cache.enable)
- toolbar.pan_end.connect(cache.disable)
- return cache
-
-
class ColormapPatchHandler(HandlerBase):
def __init__(self, cmap, nb_subpatch=10, xpad=0.0, ypad=0.0):
"""
diff --git a/glue/utils/qt/__init__.py b/glue/utils/qt/__init__.py
index 613727a41..95cc710cd 100644
--- a/glue/utils/qt/__init__.py
+++ b/glue/utils/qt/__init__.py
@@ -1,11 +1,4 @@
-from .autocomplete_widget import * # noqa
-from .dialogs import * # noqa
-from .colors import * # noqa
-from .decorators import * # noqa
-from .helpers import * # noqa
-from .mixins import * # noqa
-from .mime import * # noqa
-from .python_list_model import * # noqa
-from .threading import * # noqa
-from .app import * # noqa
-from .delegates import * # noqa
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.utils.qt is deprecated, use glue_qt.utils instead', GlueDeprecationWarning)
+from glue_qt.utils import * # noqa
diff --git a/glue/utils/qt/app.py b/glue/utils/qt/app.py
index c01068da9..1ade6b52a 100644
--- a/glue/utils/qt/app.py
+++ b/glue/utils/qt/app.py
@@ -1,97 +1,4 @@
-import time
-import platform
-from qtpy import QtCore, QtGui, QtWidgets
-
-from glue.config import settings
-from glue._settings_helpers import save_settings
-
-__all__ = ['process_events', 'get_qapp', 'fix_tab_widget_fontsize', 'update_global_font_size']
-
-qapp = None
-
-
-def __get_font_size_offset():
- if platform.system() == 'Darwin':
- # On Mac, the fonts are generally too large compared to other
- # applications, so we reduce the default here. In future we should
- # make this a setting in the system preferences.
- size_offset = 2
- else:
- # On other platforms, we reduce the font size by 1 point to save
- # space too. Again, this should probably be a global setting.
- size_offset = 1
- return size_offset
-
-
-def process_events(wait=None):
- app = get_qapp()
- if wait is None:
- app.processEvents()
- else:
- start = time.time()
- while time.time() - start < wait:
- app.processEvents()
-
-
-def get_qapp(icon_path=None):
-
- global qapp
-
- qapp = QtWidgets.QApplication.instance()
-
- if qapp is None:
-
- # NOTE: plugins that need WebEngine may complain that QtWebEngineWidgets
- # needs to be imported before QApplication is constructed, but this can
- # cause segmentation faults to crop up under certain conditions, so we
- # don't do it here and instead ask that the plugins do it in their
- # main __init__.py (which should get executed before glue is launched).
-
- qapp = QtWidgets.QApplication([''])
- qapp.setQuitOnLastWindowClosed(True)
-
- if icon_path is not None:
- qapp.setWindowIcon(QtGui.QIcon(icon_path))
-
- size_offset = __get_font_size_offset()
- font = qapp.font()
-
- if settings.FONT_SIZE is None or settings.FONT_SIZE == -1:
- default_font = QtGui.QFont()
- settings.FONT_SIZE = default_font.pointSize()
- save_settings()
-
- point_size = settings.FONT_SIZE
- font.setPointSize(int(point_size - size_offset))
- qapp.setFont(font)
-
- # Make sure we use high resolution icons for HDPI displays.
- try:
- qapp.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps)
- except AttributeError: # PyQt6/PySide6 don't have this setting as it is default
- pass
-
- return qapp
-
-
-def fix_tab_widget_fontsize(tab_widget):
- """
- Because of a bug in Qt, tab titles on MacOS X don't have the right font size
- """
- if platform.system() == 'Darwin':
- app = get_qapp()
- app_font = app.font()
- tab_widget.setStyleSheet('font-size: {0}px'.format(app_font.pointSize()))
-
-
-def update_global_font_size():
- """Updates the global font size through the current UI backend
- """
- if qapp is None:
- get_qapp()
-
- font = qapp.font()
- point_size = settings.FONT_SIZE
- size_offset = __get_font_size_offset()
- font.setPointSize(int(point_size - size_offset))
- qapp.setFont(font)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.utils.qt.app is deprecated, use glue_qt.utils.app instead', GlueDeprecationWarning)
+from glue_qt.utils.app import * # noqa
diff --git a/glue/utils/qt/autocomplete_widget.py b/glue/utils/qt/autocomplete_widget.py
index e67a5afe0..07c699e3a 100644
--- a/glue/utils/qt/autocomplete_widget.py
+++ b/glue/utils/qt/autocomplete_widget.py
@@ -1,116 +1,4 @@
-# Code adapted from:
-#
-# http://rowinggolfer.blogspot.de/2010/08/qtextedit-with-autocompletion-using.html
-#
-# and based on:
-#
-# http://qt-project.org/doc/qt-4.8/tools-customcompleter.html
-
-from qtpy import QtGui, QtWidgets
-from qtpy.QtCore import Qt
-
-
-__all__ = ["CompletionTextEdit"]
-
-
-class CompletionTextEdit(QtWidgets.QTextEdit):
-
- def __init__(self, parent=None):
-
- super(CompletionTextEdit, self).__init__(parent)
-
- self.setMinimumWidth(400)
- self.completer = None
- self.word_list = None
-
- self.moveCursor(QtGui.QTextCursor.End)
-
- def set_word_list(self, word_list):
- self.word_list = word_list
- self.set_completer(QtWidgets.QCompleter(word_list))
-
- def set_completer(self, completer):
-
- if self.completer:
- self.disconnect(self.completer, 0, self, 0)
- if not completer:
- return
-
- self.completer = completer
-
- self.completer.setWidget(self)
- self.completer.setCompletionMode(QtWidgets.QCompleter.PopupCompletion)
- self.completer.setCaseSensitivity(Qt.CaseInsensitive)
- self.completer.activated.connect(self.insert_completion)
-
- def insert_completion(self, completion):
-
- tc = self.textCursor()
-
- existing = self.text_under_cursor()
-
- completion = completion[len(existing):] + " "
-
- self.setTextCursor(tc)
-
- self.insertPlainText(completion)
-
- self.completer.setCompletionPrefix('')
-
- def text_under_cursor(self):
- tc = self.textCursor()
- text = self.toPlainText()
- pos1 = tc.position()
- if pos1 == 0 or text[pos1 - 1] == ' ':
- return ''
- else:
- sub = text[:pos1]
- if ' ' in sub:
- pos2 = sub.rindex(' ')
- return sub[pos2 + 1:]
- else:
- return sub
-
- # The following methods override methods in QTextEdit and should not be
- # renamed.
-
- def focusInEvent(self, event):
- if self.completer:
- self.completer.setWidget(self)
- QtWidgets.QTextEdit.focusInEvent(self, event)
-
- def keyPressEvent(self, event):
-
- if self.completer and self.completer.popup().isVisible():
- if event.key() in (
- Qt.Key_Enter,
- Qt.Key_Return,
- Qt.Key_Escape,
- Qt.Key_Tab,
- Qt.Key_Backtab):
- event.ignore()
- return
-
- # Check if TAB has been pressed
- is_shortcut = event.key() == Qt.Key_Tab
-
- if not self.completer or not is_shortcut:
- QtWidgets.QTextEdit.keyPressEvent(self, event)
- return
-
- eow = "~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="
-
- completion_prefix = self.text_under_cursor()
-
- if not is_shortcut and (len(event.text()) == 0 or event.text()[-1:] in eow):
- self.completer.popup().hide()
- return
-
- self.completer.setCompletionPrefix(completion_prefix)
- popup = self.completer.popup()
- popup.setCurrentIndex(self.completer.completionModel().index(0, 0))
-
- cr = self.cursorRect()
- cr.setWidth(self.completer.popup().sizeHintForColumn(0) +
- self.completer.popup().verticalScrollBar().sizeHint().width())
- self.completer.complete(cr)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.utils.qt.autocomplete_widget is deprecated, use glue_qt.utils.autocomplete_widget instead', GlueDeprecationWarning)
+from glue_qt.utils.autocomplete_widget import * # noqa
diff --git a/glue/utils/qt/colors.py b/glue/utils/qt/colors.py
index daa62d712..acd5d2aad 100644
--- a/glue/utils/qt/colors.py
+++ b/glue/utils/qt/colors.py
@@ -1,220 +1,4 @@
-import numpy as np
-from matplotlib.colors import ColorConverter
-
-from glue import config
-from qtpy import QtCore, QtWidgets, QtGui
-from echo import add_callback
-from glue.utils import nonpartial
-from glue.utils.qt.widget_properties import WidgetProperty
-
-from matplotlib import cm
-
-__all__ = ['mpl_to_qt_color', 'qt_to_mpl_color', 'cmap2pixmap',
- 'tint_pixmap', 'QColorBox', 'ColorProperty', 'connect_color',
- 'QColormapCombo']
-
-
-def mpl_to_qt_color(color, alpha=None):
- """
- Convert a matplotlib color string into a Qt QColor object
-
- Parameters
- ----------
- color : str
- A color specification that matplotlib understands
- alpha : float
- Optional opacity. Float in range [0,1]
-
- Returns
- -------
- qcolor : ``QColor``
- A QColor object representing the converted color
- """
- if color in [None, 'none', 'None']:
- return QtGui.QColor(0, 0, 0, 0)
-
- cc = ColorConverter()
- r, g, b, a = cc.to_rgba(color)
- if alpha is not None:
- a = alpha
- return QtGui.QColor(int(r * 255), int(g * 255), int(b * 255), int(a * 255))
-
-
-def qt_to_mpl_color(qcolor):
- """
- Convert a QColor object into a string that matplotlib understands
-
- Note: This ignores opacity
-
- Parameters
- ----------
- qcolor : ``QColor``
- The Qt color
-
- Returns
- -------
- color : str
- A hex string describing that color
- """
- hexid = qcolor.name()
- return str(hexid)
-
-
-def cmap2pixmap(cmap, steps=50, size=(100, 100)):
- """
- Convert a matplotlib colormap into a QPixmap
-
- Parameters
- ----------
- cmap : :class:`matplotlib.colors.Colormap`
- The colormap to use
- steps : int
- The number of color steps in the output. Default=50
-
- Returns
- -------
- pixmap : ``QPixmap``
- The QPixmap instance
- """
- sm = cm.ScalarMappable(cmap=cmap)
- sm.norm.vmin = 0.0
- sm.norm.vmax = 1.0
- inds = np.linspace(0, 1, steps)
- rgbas = sm.to_rgba(inds)
- rgbas = [QtGui.QColor(int(r * 255), int(g * 255),
- int(b * 255), int(a * 255)).rgba() for r, g, b, a in rgbas]
- im = QtGui.QImage(steps, 1, QtGui.QImage.Format_Indexed8)
- im.setColorTable(rgbas)
- for i in range(steps):
- im.setPixel(i, 0, i)
- im = im.scaled(*size)
- pm = QtGui.QPixmap.fromImage(im)
- return pm
-
-
-def tint_pixmap(bm, color):
- """
- Re-color a monochrome pixmap object using `color`
-
- Parameters
- ----------
- bm : ``QBitmap``
- The Pixmap object
- color : ``QColor``
- The Qt color
-
- Returns
- -------
- pixmap : ``QPixmap``
- The new pixmap
- """
- if bm.depth() != 1:
- raise TypeError("Input pixmap must have a depth of 1: %i" % bm.depth())
-
- image = bm.toImage()
- image.setColor(1, color.rgba())
- image.setColor(0, QtGui.QColor(0, 0, 0, 0).rgba())
-
- result = QtGui.QPixmap.fromImage(image)
- return result
-
-
-class ColorProperty(WidgetProperty):
-
- def getter(self, widget):
- return widget.color()
-
- def setter(self, widget, value):
- widget.setColor(value)
-
-
-def connect_color(client, prop, widget):
-
- def update_widget(text):
- widget.setColor(text)
-
- def update_prop():
- setattr(client, prop, widget.color())
-
- add_callback(client, prop, update_widget)
- widget.colorChanged.connect(nonpartial(update_prop))
- update_widget(getattr(client, prop))
-
-
-from echo.qt.autoconnect import HANDLERS
-HANDLERS['color'] = connect_color
-
-
-class QColorBox(QtWidgets.QLabel):
-
- mousePressed = QtCore.Signal()
- colorChanged = QtCore.Signal()
-
- def __init__(self, *args, **kwargs):
- super(QColorBox, self).__init__(*args, **kwargs)
- self.mousePressed.connect(nonpartial(self.query_color))
- self.colorChanged.connect(nonpartial(self.on_color_change))
- self.setColor("#000000")
-
- def mousePressEvent(self, event):
- self.mousePressed.emit()
- event.accept()
-
- def query_color(self):
- color = QtWidgets.QColorDialog.getColor(self._qcolor, parent=self)
- if color.isValid():
- self.setColor(qt_to_mpl_color(color))
-
- def setColor(self, color):
- self._color = color
- self.colorChanged.emit()
-
- def color(self):
- return self._color
-
- def on_color_change(self):
- self._qcolor = mpl_to_qt_color(self.color())
- image = QtGui.QImage(70, 22, QtGui.QImage.Format_RGB32)
- try:
- image.fill(self._qcolor)
- except TypeError:
- # PySide and old versions of PyQt require a RGBA integer
- image.fill(self._qcolor.rgba())
- pixmap = QtGui.QPixmap.fromImage(image)
- self.setPixmap(pixmap)
-
-
-from echo.qt.connect import UserDataWrapper
-
-
-class QColormapCombo(QtWidgets.QComboBox):
-
- def __init__(self, *args, **kwargs):
- super(QColormapCombo, self).__init__(*args, **kwargs)
- for label, cmap in config.colormaps:
- self.addItem(label, userData=UserDataWrapper(cmap))
- self._update_icons()
-
- def _update_icons(self):
- self.setIconSize(QtCore.QSize(self.width(), 15))
- for index in range(self.count()):
- cmap = self.itemData(index).data
- icon = QtGui.QIcon(cmap2pixmap(cmap, size=(self.width(), 15), steps=200))
- self.setItemIcon(index, icon)
-
- def resizeEvent(self, *args, **kwargs):
- super(QColormapCombo, self).resizeEvent(*args, **kwargs)
- self._update_icons()
-
-
-if __name__ == "__main__":
-
- from glue.utils.qt import get_qapp
-
- app = get_qapp()
-
- label = QColorBox()
- label.resize(100, 100)
- label.show()
- label.raise_()
- app.exec_()
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.utils.qt.colors is deprecated, use glue_qt.utils.colors instead', GlueDeprecationWarning)
+from glue_qt.utils.colors import * # noqa
diff --git a/glue/utils/qt/decorators.py b/glue/utils/qt/decorators.py
index f4eff8b51..36f64a5d1 100644
--- a/glue/utils/qt/decorators.py
+++ b/glue/utils/qt/decorators.py
@@ -1,101 +1,4 @@
-import os
-import sys
-import traceback
-from contextlib import contextmanager
-from functools import wraps
-
-__all__ = ['set_cursor', 'set_cursor_cm', 'messagebox_on_error',
- 'die_on_error']
-
-
-def set_cursor(shape):
- """Set the Qt cursor for the duration of a function call, and unset
-
- :param shape: Cursor shape to set.
- """
- def wrapper(func):
- @wraps(func)
- def result(*args, **kwargs):
- from glue.utils.qt import get_qapp # Here to avoid circ import
- app = get_qapp()
- app.setOverrideCursor(shape)
- try:
- return func(*args, **kwargs)
- finally:
- app.restoreOverrideCursor()
- return result
-
- return wrapper
-
-
-# TODO: Does this really belong in this module?
-@contextmanager
-def set_cursor_cm(shape):
- """Context manager equivalent for :func:`set_cursor`."""
- from glue.utils.qt import get_qapp
- app = get_qapp()
- app.setOverrideCursor(shape)
- try:
- yield
- finally:
- app.restoreOverrideCursor()
-
-
-# TODO: We should be able to avoid defining these as classes and defining
-# __call__ below, by using contextmanager.
-
-class messagebox_on_error(object):
-
- def __init__(self, msg, sep='\n', exit=False):
- self.msg = msg
- self.sep = sep
- self.exit = exit
-
- def __call__(self, f):
- @wraps(f)
- def decorated(*args, **kwargs):
- # If we are in glue testing mode, just execute function
- if os.environ.get("GLUE_TESTING") == 'True':
- return f(*args, **kwargs)
- with self:
- return f(*args, **kwargs)
- return decorated
-
- def __enter__(self):
- pass
-
- def __exit__(self, exc_type, exc_val, tb):
-
- if exc_type is None:
- return
-
- # Make sure application has been started
- from glue.utils.qt import get_qapp # Here to avoid circular import
- get_qapp()
-
- m = "%s\n%s" % (self.msg, exc_val)
- detail = ''.join(traceback.format_exception(exc_type, exc_val, tb))
- if len(m) > 500:
- detail = "Full message:\n\n%s\n\n%s" % (m, detail)
- m = m[:500] + '...'
-
- from qtpy import QtWidgets
- from qtpy.QtCore import Qt
-
- qmb = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Critical, "Error", m)
- qmb.setDetailedText(detail)
- qmb.resize(400, qmb.size().height())
- qmb.setTextInteractionFlags(Qt.TextSelectableByMouse)
- qmb.exec_()
-
- if self.exit:
- sys.exit(1)
-
- # Just for cases where we are testing and patching sys.exit
- return True
-
-
-class die_on_error(messagebox_on_error):
-
- def __init__(self, msg):
- super(die_on_error, self).__init__(msg, exit=True)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.utils.qt.decorators is deprecated, use glue_qt.utils.decorators instead', GlueDeprecationWarning)
+from glue_qt.utils.decorators import * # noqa
diff --git a/glue/utils/qt/delegates.py b/glue/utils/qt/delegates.py
index 76f1ea7fb..8906740dc 100644
--- a/glue/utils/qt/delegates.py
+++ b/glue/utils/qt/delegates.py
@@ -1,60 +1,4 @@
-from qtpy import QtWidgets, QtGui, QtCore
-
-
-class HtmlItemDelegate(QtWidgets.QStyledItemDelegate):
- """
- An item delegate that can be used for e.g. QTreeView, QTreeWidget,
- QListView or QListWidget. This will automatically interpret any HTML that
- is inside the items in these views/widgets.
-
- This is more efficient than using e.g. QLabel instances embedded in the
- views/widgets, and is required for horizontal scroll bars to appear
- correctly.
- """
-
- # Implementation adapted based on solutions presented on StackOverflow:
- # https://stackoverflow.com/questions/1956542/how-to-make-item-view-render-rich-html-text-in-qt
-
- def paint(self, painter, option, index):
-
- options = QtWidgets.QStyleOptionViewItem(option)
- self.initStyleOption(options, index)
-
- painter.save()
-
- doc = QtGui.QTextDocument()
- doc.setTextWidth(options.rect.width())
-
- text_option = QtGui.QTextOption()
- text_option.setWrapMode(QtGui.QTextOption.NoWrap)
- text_option.setAlignment(options.displayAlignment)
- doc.setDefaultTextOption(text_option)
-
- doc.setHtml(options.text)
-
- options.text = ""
- options.widget.style().drawControl(QtWidgets.QStyle.CE_ItemViewItem, options, painter)
-
- iconSize = options.icon.actualSize(options.rect.size())
- painter.translate(options.rect.left() + iconSize.width(), options.rect.top())
- clip = QtCore.QRectF(0, 0, options.rect.width() + iconSize.width(), options.rect.height())
-
- doc.drawContents(painter, clip)
-
- painter.restore()
-
- def sizeHint(self, option, index):
-
- options = QtWidgets.QStyleOptionViewItem(option)
- self.initStyleOption(options, index)
-
- doc = QtGui.QTextDocument()
-
- text_option = QtGui.QTextOption()
- text_option.setWrapMode(QtGui.QTextOption.NoWrap)
- doc.setDefaultTextOption(text_option)
-
- doc.setHtml(options.text)
- doc.setTextWidth(options.rect.width())
-
- return QtCore.QSize(doc.idealWidth(), doc.size().height())
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.utils.qt.delegates is deprecated, use glue_qt.utils.delegates instead', GlueDeprecationWarning)
+from glue_qt.utils.delegates import * # noqa
diff --git a/glue/utils/qt/dialogs.py b/glue/utils/qt/dialogs.py
index 2d6081c9f..dcd1d13b9 100644
--- a/glue/utils/qt/dialogs.py
+++ b/glue/utils/qt/dialogs.py
@@ -1,99 +1,4 @@
-from qtpy import QtWidgets
-
-__all__ = ['pick_item', 'pick_class', 'get_text', 'CenteredDialog']
-
-
-def pick_item(items, labels, title="Pick an item", label="Pick an item",
- default=None):
- """
- Prompt the user to choose an item
-
- Returns the selected item, or `None`
-
- Parameters
- ----------
- items : iterable
- Items to choose (can be any Python object)
- labels : iterables
- Labels for the items to choose
- title : str, optional
- The title of the dialog
- label : str, optional
- The prompt message
- """
-
- if default in items:
- current = items.index(default)
- else:
- current = 0
-
- choice, isok = QtWidgets.QInputDialog.getItem(None, title, label,
- labels, current=current,
- editable=False)
- if isok:
- index = labels.index(str(choice))
- return items[index]
-
-
-def pick_class(classes, sort=False, **kwargs):
- """
- Prompt the user to pick from a list of classes using Qt
-
- This is the same as `pick_item`, but the labels are automatically determined
- from the classes using the LABEL attribute, and if not set, then the
- __name__.
-
- Returns the class that was selected, or `None`
-
- Parameters
- ----------
- classes : iterable
- The classes to choose from
- title : str, optional
- The title of the dialog
- label : str, optional
- The prompt message
- """
- def _label(c):
- try:
- return c.LABEL
- except AttributeError:
- return c.__name__
-
- if sort:
- classes = sorted(classes, key=lambda x: _label(x))
- choices = [_label(c) for c in classes]
- return pick_item(classes, choices, **kwargs)
-
-
-def get_text(title='Enter a label', default=None):
- """
- Prompt the user to enter text using Qt
-
- Returns the text the user typed, or `None`
-
- Parameters
- ----------
- title : str
- The prompt message and widget title.
- default : str
- The default text to show in the prompt.
- """
- result, isok = QtWidgets.QInputDialog.getText(None, title, title, text=default)
- if isok:
- return str(result)
-
-
-class CenteredDialog(QtWidgets.QDialog):
- """
- A dialog that is centered on the screen.
- """
-
- def center(self):
- # Adapted from StackOverflow
- # https://stackoverflow.com/questions/20243637/pyqt4-center-window-on-active-screen
- frameGm = self.frameGeometry()
- screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
- centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
- frameGm.moveCenter(centerPoint)
- self.move(frameGm.topLeft())
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.utils.qt.dialogs is deprecated, use glue_qt.utils.dialogs instead', GlueDeprecationWarning)
+from glue_qt.utils.dialogs import * # noqa
diff --git a/glue/utils/qt/helpers.py b/glue/utils/qt/helpers.py
index 0b6fc238b..07138b9d9 100644
--- a/glue/utils/qt/helpers.py
+++ b/glue/utils/qt/helpers.py
@@ -1,229 +1,4 @@
-import os
-import sys
-from contextlib import contextmanager
-
-from qtpy import QtCore, QtWidgets
-from qtpy.QtCore import Qt
-from qtpy.uic import loadUi
-from glue.utils.qt import get_text
-
-__all__ = ['update_combobox', 'GlueTabBar', 'load_ui', 'process_dialog',
- 'combo_as_string', 'qurl_to_path']
-
-
-def update_combobox(combo, labeldata, default_index=0, block_signals=True):
- """
- Redefine the items in a QComboBox
-
- Parameters
- ----------
- widget : QComboBox
- The widget to update
- labeldata : sequence of N (label, data) tuples
- The combobox will contain N items with the appropriate
- labels, and data set as the userData
-
- Returns
- -------
- combo : QComboBox
- The updated input
-
- Notes
- -----
-
- If the current userData in the combo box matches
- any of labeldata, that selection will be retained.
- Otherwise, the first item will be selected.
-
- Signals are disabled while the combo box is updated
-
- The QComboBox is modified inplace
- """
-
- if block_signals:
- combo.blockSignals(True)
- idx = combo.currentIndex()
- if idx >= 0:
- current = combo.itemData(idx)
- else:
- current = None
-
- combo.clear()
- index = None
- for i, (label, data) in enumerate(labeldata):
- combo.addItem(label, userData=data)
- if data is current or data == current:
- index = i
-
- if default_index < 0:
- default_index = combo.count() + default_index
-
- if index is None:
- index = min(default_index, combo.count() - 1)
- combo.setCurrentIndex(index)
-
- if block_signals:
- combo.blockSignals(False)
-
- # We need to force emit this, otherwise if the index happens to be the
- # same as before, even if the data is different, callbacks won't be
- # called. So we block the signals until just before now then always call
- # callback manually.
- combo.currentIndexChanged.emit(index)
-
-
-class GlueTabBar(QtWidgets.QTabBar):
-
- def __init__(self, *args, **kwargs):
- super(GlueTabBar, self).__init__(*args, **kwargs)
-
- def choose_rename_tab(self, index=None):
- """
- Prompt user to rename a tab
-
- Parameters
- ----------
- index : int
- Index of tab to edit. Defaults to current index
- """
- index = index or self.currentIndex()
- label = get_text("New Tab Label")
- if not label:
- return
- self.rename_tab(index, label)
-
- def rename_tab(self, index, label):
- """
- Updates the name used for given tab
-
- Parameters
- ----------
- index : int
- Index of tab to edit. Defaults to current index
- label : str
- New label to use for this tab
- """
- self.setTabText(index, label)
-
- def mouseDoubleClickEvent(self, event):
- if event.button() != Qt.LeftButton:
- return
- index = self.tabAt(event.pos())
- if index >= 0:
- self.choose_rename_tab(index)
-
-
-def load_ui(path, parent=None, directory=None):
- """
- Load a .ui file
-
- Parameters
- ----------
- path : str
- Name of ui file to load
-
- parent : QObject
- Object to use as the parent of this widget
-
- Returns
- -------
- w
- The new widget
- """
-
- if directory is not None:
- full_path = os.path.join(directory, path)
- else:
- full_path = os.path.abspath(path)
-
- if not os.path.exists(full_path) and 'site-packages.zip' in full_path:
- # Workaround for Mac app
- full_path = os.path.join(full_path.replace('site-packages.zip', 'glue'))
-
- return loadUi(full_path, parent)
-
-
-@contextmanager
-def process_dialog(delay=0, accept=False, reject=False, function=None):
- """
- Context manager to automatically capture the active dialog and carry out
- certain actions.
-
- Note that only one of ``accept``, ``reject``, or ``function`` should be
- specified.
-
- Parameters
- ----------
- delay : int, optional
- The delay in ms before acting on the dialog (since it may not yet exist
- when the context manager is called).
- accept : bool, optional
- If `True`, accept the dialog after the specified delay.
- reject : bool, optional
- If `False`, reject the dialog after the specified delay
- function : func, optional
- For more complex user actions, specify a function that takes the dialog
- as the first and only argument.
- """
-
- def _accept(dialog):
- dialog.accept()
-
- def _reject(dialog):
- dialog.reject()
-
- n_args = sum((accept, reject, function is not None))
-
- if n_args > 1:
- raise ValueError("Only one of ``accept``, ``reject``, or "
- "``function`` should be specified")
- elif n_args == 0:
- raise ValueError("One of ``accept``, ``reject``, or "
- "``function`` should be specified")
-
- if accept:
- function = _accept
- elif reject:
- function = _reject
-
- def wrapper():
- from glue.utils.qt import get_qapp
- app = get_qapp()
- # Make sure that any window/dialog that needs to be shown is shown
- app.processEvents()
- dialog = app.activeWindow()
- function(dialog)
-
- timer = QtCore.QTimer()
- timer.setInterval(delay)
- timer.setSingleShot(True)
- timer.timeout.connect(wrapper)
- timer.start()
-
- yield
-
-
-def combo_as_string(combo):
- """
- Return the text labels of a combo box as a string to make it easier to
- check the content of a combo box in tests.
- """
- items = [combo.itemText(i) for i in range(combo.count())]
- return ":".join(items)
-
-
-def qurl_to_path(url):
- """
- Convert a local QUrl to a normal path
- """
-
- # Get path to file
- path = url.path()
-
- # Workaround for a Qt bug that causes paths to start with a /
- # on Windows: https://bugreports.qt.io/browse/QTBUG-46417
- if sys.platform.startswith('win'):
- if path.startswith('/') and path[2] == ':':
- path = path[1:]
-
- return path
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.utils.qt.helpers is deprecated, use glue_qt.utils.helpers instead', GlueDeprecationWarning)
+from glue_qt.utils.helpers import * # noqa
diff --git a/glue/utils/qt/mime.py b/glue/utils/qt/mime.py
index 939df4b09..10a67dd2b 100644
--- a/glue/utils/qt/mime.py
+++ b/glue/utils/qt/mime.py
@@ -1,56 +1,4 @@
-from qtpy import QtCore
-
-__all__ = ['PyMimeData']
-
-
-class PyMimeData(QtCore.QMimeData):
- """
- A custom MimeData object that stores live python objects
-
- Associate specific objects with a mime type by passing
- mime type / object key/value pairs to the __init__ method
-
- If a single object is passed to the init method, that
- object is associated with the PyMimeData.MIME_TYPE mime type
- """
- MIME_TYPE = 'application/py_instance'
-
- def __init__(self, instance=None, **kwargs):
- """
- :param instance: The python object to store
-
- kwargs: Optional mime type / objects pairs to store as objects
- """
- super(PyMimeData, self).__init__()
-
- self._instances = {}
-
- self.setData(self.MIME_TYPE, instance)
- for k, v in kwargs.items():
- self.setData(k, v)
-
- def formats(self):
- return list(set(super(PyMimeData, self).formats() +
- list(self._instances.keys())))
-
- def hasFormat(self, fmt):
- return fmt in self._instances or super(PyMimeData, self).hasFormat(fmt)
-
- def setData(self, mime, data):
- try:
- super(PyMimeData, self).setData(mime, QtCore.QByteArray(1, b'1'))
- except TypeError: # PySide6
- super(PyMimeData, self).setData(mime, QtCore.QByteArray(b'1'))
-
- self._instances[mime] = data
-
- def data(self, mime_type):
- """ Retrieve the data stored at the specified mime_type
-
- If mime_type is application/py_instance, a python object
- is returned. Otherwise, a QtCore.QByteArray is returned """
-
- if str(mime_type) in self._instances:
- return self._instances[mime_type]
-
- return super(PyMimeData, self).data(mime_type)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.utils.qt.mime is deprecated, use glue_qt.utils.mime instead', GlueDeprecationWarning)
+from glue_qt.utils.mime import * # noqa
diff --git a/glue/utils/qt/mixins.py b/glue/utils/qt/mixins.py
index b780b5041..0037a89ae 100644
--- a/glue/utils/qt/mixins.py
+++ b/glue/utils/qt/mixins.py
@@ -1,74 +1,4 @@
-from glue.utils.qt.mime import PyMimeData
-
-__all__ = ['GlueItemWidget']
-
-
-class GlueItemWidget(object):
-
- """
- A mixin for QtWidgets.QListWidget/GlueTreeWidget subclasses, that provides
- drag+drop functionality.
- """
- # Implementation detail: QXXWidgetItems are unhashable in PySide,
- # and cannot be used as dictionary keys. we hash on IDs instead
-
- SUPPORTED_MIME_TYPE = None
-
- def __init__(self, parent=None):
- super(GlueItemWidget, self).__init__(parent)
- self._mime_data = {}
- self.setDragEnabled(True)
-
- def mimeTypes(self):
- """
- Return the list of MIME Types supported for this object.
- """
- types = [self.SUPPORTED_MIME_TYPE]
- return types
-
- def mimeData(self, selected_items):
- """
- Return a list of MIME data associated with the each selected item.
-
- Parameters
- ----------
- selected_items : list
- A list of ``QtWidgets.QListWidgetItems`` or ``QtWidgets.QTreeWidgetItems`` instances
-
- Returns
- -------
- result : list
- A list of MIME objects
- """
- try:
- data = [self.get_data(i) for i in selected_items]
- except KeyError:
- data = None
- result = PyMimeData(data, **{self.SUPPORTED_MIME_TYPE: data})
-
- # apparent bug in pyside garbage collects custom mime
- # data, and crashes. Save result here to avoid
- self._mime = result
-
- return result
-
- def get_data(self, item):
- """
- Convenience method to fetch the data associated with a ``QxxWidgetItem``.
- """
- # return item.data(Qt.UserRole)
- return self._mime_data.get(id(item), None)
-
- def set_data(self, item, data):
- """
- Convenience method to set data associated with a ``QxxWidgetItem``.
- """
- # item.setData(Qt.UserRole, data)
- self._mime_data[id(item)] = data
-
- def drop_data(self, item):
- self._mime_data.pop(id(item))
-
- @property
- def data(self):
- return self._mime_data
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.utils.qt.mixins is deprecated, use glue_qt.utils.mixins instead', GlueDeprecationWarning)
+from glue_qt.utils.mixins import * # noqa
diff --git a/glue/utils/qt/python_list_model.py b/glue/utils/qt/python_list_model.py
index faeeabc06..a3ad8699b 100644
--- a/glue/utils/qt/python_list_model.py
+++ b/glue/utils/qt/python_list_model.py
@@ -1,151 +1,4 @@
-from qtpy import QtCore
-from qtpy.QtCore import Qt
-
-__all__ = ['PythonListModel']
-
-
-class PythonListModel(QtCore.QAbstractListModel):
-
- """
- A Qt Model that wraps a python list, and exposes a list-like interface
-
- This can be connected directly to multiple QListViews, which will
- stay in sync with the state of the container.
- """
-
- def __init__(self, items, parent=None):
- """
- Create a new model
-
- Parameters
- ----------
- items : list
- The initial list to wrap
- parent : QObject
- The model parent
- """
- super(PythonListModel, self).__init__(parent)
- self.items = items
-
- def rowCount(self, parent=None):
- """Number of rows"""
- return len(self.items)
-
- def headerData(self, section, orientation, role):
- """Column labels"""
- if role != Qt.DisplayRole:
- return None
- return "%i" % section
-
- def row_label(self, row):
- """ The textual label for the row"""
- return str(self.items[row])
-
- def data(self, index, role):
- """Retrieve data at each index"""
- if not index.isValid():
- return None
- if role == Qt.DisplayRole or role == Qt.EditRole:
- return self.row_label(index.row())
- if role == Qt.UserRole:
- return self.items[index.row()]
-
- def setData(self, index, value, role):
- """
- Update the data in-place
-
- Parameters
- ----------
- index : QModelIndex
- The location of the change
- value : object
- The new value
- role : QEditRole
- Which aspect of the model to update
- """
- if not index.isValid():
- return False
-
- if role == Qt.UserRole:
- row = index.row()
- self.items[row] = value
- self.dataChanged.emit(index, index)
- return True
-
- return super(PythonListModel, self).setData(index, value, role)
-
- def removeRow(self, row, parent=None):
- """
- Remove a row from the table
-
- Parameters
- ----------
- row : int
- Row to remove
-
- Returns
- -------
- successful : bool
- """
- if row < 0 or row >= len(self.items):
- return False
-
- self.beginRemoveRows(QtCore.QModelIndex(), row, row)
- self._remove_row(row)
- self.endRemoveRows()
- return True
-
- def pop(self, row=None):
- """
- Remove and return an item (default last item)
-
- Parameters
- ----------
- row : int (optional)
- Which row to remove. Default=last
-
- Returns
- -------
- popped : object
- """
- if row is None:
- row = len(self) - 1
- result = self[row]
- self.removeRow(row)
- return result
-
- def _remove_row(self, row):
- # actually remove data. Subclasses can override this as needed
- self.items.pop(row)
-
- def __getitem__(self, row):
- return self.items[row]
-
- def __setitem__(self, row, value):
- index = self.index(row)
- self.setData(index, value, role=Qt.UserRole)
-
- def __len__(self):
- return len(self.items)
-
- def insert(self, row, value):
- self.beginInsertRows(QtCore.QModelIndex(), row, row)
- self.items.insert(row, value)
- self.endInsertRows()
- self.rowsInserted.emit(self.index(row), row, row)
-
- def append(self, value):
- row = len(self)
- self.insert(row, value)
-
- def extend(self, values):
- for v in values:
- self.append(v)
-
- def set_list(self, values):
- """
- Set the model to a new list
- """
- self.beginResetModel()
- self.items = values
- self.endResetModel()
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.utils.qt.python_list_model is deprecated, use glue_qt.utils.python_list_model instead', GlueDeprecationWarning)
+from glue_qt.utils.python_list_model import * # noqa
diff --git a/glue/utils/qt/tests/__init__.py b/glue/utils/qt/tests/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/glue/utils/qt/tests/test_colors.py b/glue/utils/qt/tests/test_colors.py
deleted file mode 100644
index e4e102118..000000000
--- a/glue/utils/qt/tests/test_colors.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from unittest.mock import MagicMock
-
-from echo import CallbackProperty
-from qtpy import QtGui
-
-from ..colors import qt_to_mpl_color, QColorBox, connect_color, QColormapCombo
-
-
-def test_colors():
- assert qt_to_mpl_color(QtGui.QColor(255, 0, 0)) == '#ff0000'
- assert qt_to_mpl_color(QtGui.QColor(255, 255, 255)) == '#ffffff'
-
-
-# TODO: add a test for the other way around
-
-# TODO: add a test for cmap2pixmap
-
-# TODO: add a test for tint_pixmap
-
-def test_color_box():
-
- func = MagicMock()
-
- label = QColorBox()
- label.resize(100, 100)
- label.colorChanged.connect(func)
- label.setColor('#472822')
-
- assert func.call_count == 1
-
-
-def test_connect_color():
-
- class FakeClass(object):
- color = CallbackProperty()
-
- c = FakeClass()
-
- label = QColorBox()
-
- connect_color(c, 'color', label)
-
- label.setColor('#472822')
-
- assert c.color == '#472822'
-
- c.color = '#012345'
-
- assert label.color() == '#012345'
-
-
-def test_colormap_combo():
-
- combo = QColormapCombo()
diff --git a/glue/utils/qt/tests/test_decorators.py b/glue/utils/qt/tests/test_decorators.py
deleted file mode 100644
index 1a3a2d1fd..000000000
--- a/glue/utils/qt/tests/test_decorators.py
+++ /dev/null
@@ -1,98 +0,0 @@
-import os
-from unittest.mock import patch
-
-from ..decorators import messagebox_on_error, die_on_error
-
-
-def test_messagebox_on_error():
-
- os.environ['GLUE_TESTING'] = 'False'
-
- def failing_function():
- raise ValueError("Dialog failure")
-
- def working_function():
- pass
-
- @messagebox_on_error('An error occurred')
- def decorated_failing_function():
- failing_function()
-
- @messagebox_on_error('An error occurred')
- def decorated_working_function():
- working_function()
-
- # Test decorator
-
- with patch('qtpy.QtWidgets.QMessageBox') as mb:
- decorated_failing_function()
- assert mb.call_args[0][2] == 'An error occurred\nDialog failure'
-
- with patch('qtpy.QtWidgets.QMessageBox') as mb:
- decorated_working_function()
- assert mb.call_count == 0
-
- # Test context manager
-
- with patch('qtpy.QtWidgets.QMessageBox') as mb:
- with messagebox_on_error('An error occurred'):
- failing_function()
- assert mb.call_args[0][2] == 'An error occurred\nDialog failure'
-
- with patch('qtpy.QtWidgets.QMessageBox') as mb:
- with messagebox_on_error('An error occurred'):
- working_function()
- assert mb.call_count == 0
-
- os.environ['GLUE_TESTING'] = 'True'
-
-
-def test_die_on_error():
-
- os.environ['GLUE_TESTING'] = 'False'
-
- def failing_function():
- raise ValueError("Dialog failure")
-
- def working_function():
- pass
-
- @die_on_error('An error occurred')
- def decorated_failing_function():
- failing_function()
-
- @die_on_error('An error occurred')
- def decorated_working_function():
- working_function()
-
- # Test decorator
-
- with patch('sys.exit') as exit:
- with patch('qtpy.QtWidgets.QMessageBox') as mb:
- decorated_failing_function()
- assert mb.call_args[0][2] == 'An error occurred\nDialog failure'
- assert exit.called_once_with(1)
-
- with patch('sys.exit') as exit:
- with patch('qtpy.QtWidgets.QMessageBox') as mb:
- decorated_working_function()
- assert mb.call_count == 0
- assert exit.call_count == 0
-
- # Test context manager
-
- with patch('sys.exit') as exit:
- with patch('qtpy.QtWidgets.QMessageBox') as mb:
- with die_on_error('An error occurred'):
- failing_function()
- assert mb.call_args[0][2] == 'An error occurred\nDialog failure'
- assert exit.called_once_with(1)
-
- with patch('sys.exit') as exit:
- with patch('qtpy.QtWidgets.QMessageBox') as mb:
- with die_on_error('An error occurred'):
- working_function()
- assert mb.call_count == 0
- assert exit.call_count == 0
-
- os.environ['GLUE_TESTING'] = 'True'
diff --git a/glue/utils/qt/tests/test_dialogs.py b/glue/utils/qt/tests/test_dialogs.py
deleted file mode 100644
index 439143128..000000000
--- a/glue/utils/qt/tests/test_dialogs.py
+++ /dev/null
@@ -1,49 +0,0 @@
-from unittest import mock
-
-from ..dialogs import pick_item, pick_class, get_text
-
-
-def test_pick_item():
-
- items = ['a', 'b', 'c']
- labels = ['1', '2', '3']
-
- with mock.patch('qtpy.QtWidgets.QInputDialog') as d:
- d.getItem.return_value = '1', True
- assert pick_item(items, labels) == 'a'
- d.getItem.return_value = '2', True
- assert pick_item(items, labels) == 'b'
- d.getItem.return_value = '3', True
- assert pick_item(items, labels) == 'c'
- d.getItem.return_value = '3', False
- assert pick_item(items, labels) is None
-
-
-def test_pick_class():
-
- class Foo:
- pass
-
- class Bar:
- pass
-
- Bar.LABEL = 'Baz'
-
- with mock.patch('glue.utils.qt.dialogs.pick_item') as d:
- pick_class([Foo, Bar], default=Foo)
- d.assert_called_once_with([Foo, Bar], ['Foo', 'Baz'], default=Foo)
-
- with mock.patch('glue.utils.qt.dialogs.pick_item') as d:
- pick_class([Foo, Bar], sort=True)
- d.assert_called_once_with([Bar, Foo], ['Baz', 'Foo'])
-
-
-def test_get_text():
-
- with mock.patch('qtpy.QtWidgets.QInputDialog') as d:
-
- d.getText.return_value = 'abc', True
- assert get_text() == 'abc'
-
- d.getText.return_value = 'abc', False
- assert get_text() is None
diff --git a/glue/utils/qt/tests/test_helpers.py b/glue/utils/qt/tests/test_helpers.py
deleted file mode 100644
index 92e91efd3..000000000
--- a/glue/utils/qt/tests/test_helpers.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from qtpy import QtWidgets
-from ..helpers import update_combobox
-
-
-def test_update_combobox():
- combo = QtWidgets.QComboBox()
- update_combobox(combo, [('a', 1), ('b', 2)])
- update_combobox(combo, [('c', 3)])
-
-
-def test_update_combobox_indexchanged():
-
- # Regression test for bug that caused currentIndexChanged to not be
- # emitted if the new index happened to be the same as the old one but the
- # label data was different.
-
- class MyComboBox(QtWidgets.QComboBox):
-
- def __init__(self, *args, **kwargs):
- self.change_count = 0
- super(MyComboBox, self).__init__(*args, **kwargs)
- self.currentIndexChanged.connect(self.changed)
-
- def changed(self):
- self.change_count += 1
-
- combo = MyComboBox()
- update_combobox(combo, [('a', 1), ('b', 2)])
- update_combobox(combo, [('c', 3)])
-
- assert combo.change_count == 2
- assert combo.currentIndex() == 0
-
- combo = MyComboBox()
- update_combobox(combo, [('a', 1), ('b', 2)])
- update_combobox(combo, [('a', 1), ('b', 3)])
- update_combobox(combo, [('a', 3), ('b', 1)])
-
- assert combo.change_count == 3
- assert combo.currentIndex() == 1
diff --git a/glue/utils/qt/tests/test_mime.py b/glue/utils/qt/tests/test_mime.py
deleted file mode 100644
index 7a889f530..000000000
--- a/glue/utils/qt/tests/test_mime.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# import pytest
-#
-# from qtpy.QtTest import QTest
-# from qtpy.QtCore import Qt
-# from qtpy import QtWidgets
-
-from .. import mime
-
-
-INSTANCE_MIME_TYPE = mime.PyMimeData.MIME_TYPE
-TEST_MIME_TYPE_1 = 'test1/test1'
-TEST_MIME_TYPE_2 = 'test2/test2'
-
-
-class TestMime():
-
- def test_formats(self):
- d = mime.PyMimeData()
- assert set(d.formats()) == set([INSTANCE_MIME_TYPE])
-
- d = mime.PyMimeData(**{'text/plain': 'hello'})
- assert set(d.formats()) == set([INSTANCE_MIME_TYPE, 'text/plain'])
-
- def test_empty_has_format(self):
- d = mime.PyMimeData()
- assert d.hasFormat(INSTANCE_MIME_TYPE)
- assert not d.hasFormat(TEST_MIME_TYPE_1)
- assert not d.hasFormat(TEST_MIME_TYPE_2)
-
- def test_instance_format(self):
- d = mime.PyMimeData(5)
- assert d.hasFormat(INSTANCE_MIME_TYPE)
- assert not d.hasFormat(TEST_MIME_TYPE_1)
- assert not d.hasFormat(TEST_MIME_TYPE_2)
-
- def test_layer_format(self):
- d = mime.PyMimeData(5, **{TEST_MIME_TYPE_1: 10})
- assert d.hasFormat(INSTANCE_MIME_TYPE)
- assert d.hasFormat(TEST_MIME_TYPE_1)
- assert not d.hasFormat(TEST_MIME_TYPE_2)
-
- def test_layers_format(self):
- d = mime.PyMimeData(5, **{TEST_MIME_TYPE_2: 10})
- assert d.hasFormat(INSTANCE_MIME_TYPE)
- assert d.hasFormat(TEST_MIME_TYPE_2)
- assert not d.hasFormat(TEST_MIME_TYPE_1)
-
- def test_retrieve_instance(self):
- d = mime.PyMimeData(10)
- assert d.data(INSTANCE_MIME_TYPE) == 10
-
- def test_retrieve_layer(self):
- d = mime.PyMimeData(**{TEST_MIME_TYPE_2: 12})
- assert d.data(TEST_MIME_TYPE_2) == 12
-
- d = mime.PyMimeData(**{TEST_MIME_TYPE_1: 12})
- assert d.data(TEST_MIME_TYPE_1) == 12
-
- def test_retrieve_not_present_returns_null(self):
- d = mime.PyMimeData()
- assert d.data('not-a-format').size() == 0
-
-
-# class TestWidget(QtWidgets.QWidget):
-# def __init__(self, out_mime, parent=None):
-# super(TestWidget, self).__init__(parent)
-# self.setAcceptDrops(True)
-#
-# self.last_mime = None
-# self.out_mime = out_mime
-#
-# def dragEnterEvent(self, event):
-# print('drag enter')
-# event.accept()
-#
-# def dropEvent(self, event):
-# print('drop')
-# self.last_mime = event.mimeData()
-#
-# def mousePressEvent(self, event):
-# print('mouse event')
-# drag = QtWidgets.QDrag(self)
-# drag.setMimeData(self.out_mime)
-# drop_action = drag.exec_()
-# print(drop_action)
-# event.accept()
-#
-#
-# class TestMimeDragAndDrop(object):
-#
-# def setup_method(self, method):
-#
-# m1 = mime.PyMimeData(1, **{'text/plain': 'hi', 'test': 4})
-# m2 = mime.PyMimeData(1, **{'test': 5})
-#
-# w1 = TestWidget(m1)
-# w2 = TestWidget(m2)
-#
-# self.w1 = w1
-# self.w2 = w2
-# self.m1 = m1
-# self.m2 = m2
-#
-# def test_drag_drop(self):
-# QTest.mousePress(self.w1, Qt.LeftButton)
-# QTest.mouseMove(self.w2)
-# QTest.mouseRelease(self.w2, Qt.LeftButton)
-#
-# assert self.w2.last_mime == self.m1
diff --git a/glue/utils/qt/tests/test_python_list_model.py b/glue/utils/qt/tests/test_python_list_model.py
deleted file mode 100644
index e3aa17022..000000000
--- a/glue/utils/qt/tests/test_python_list_model.py
+++ /dev/null
@@ -1,84 +0,0 @@
-import pytest
-
-from qtpy.QtCore import Qt
-
-from ..python_list_model import PythonListModel
-
-
-class TestListModel(object):
-
- def test_row_count(self):
- assert PythonListModel([]).rowCount() == 0
- assert PythonListModel([1]).rowCount() == 1
- assert PythonListModel([1, 2]).rowCount() == 2
-
- def test_data_display(self):
- m = PythonListModel([1, 'a'])
- i = m.index(0)
- assert m.data(i, role=Qt.DisplayRole) == '1'
-
- i = m.index(1)
- assert m.data(i, role=Qt.DisplayRole) == 'a'
-
- def test_data_edit(self):
- m = PythonListModel([1, 'a'])
- i = m.index(0)
- assert m.data(i, role=Qt.EditRole) == '1'
-
- i = m.index(1)
- assert m.data(i, role=Qt.EditRole) == 'a'
-
- def test_data_user(self):
- m = PythonListModel([1, 'a'])
- i = m.index(0)
- assert m.data(i, role=Qt.UserRole) == 1
-
- i = m.index(1)
- assert m.data(i, role=Qt.UserRole) == 'a'
-
- def test_itemget(self):
- m = PythonListModel([1, 'a'])
- assert m[0] == 1
- assert m[1] == 'a'
-
- def test_itemset(self):
- m = PythonListModel([1, 'a'])
- m[0] = 'b'
- assert m[0] == 'b'
-
- @pytest.mark.parametrize('items', ([], [1, 2, 3], [1]))
- def test_len(self, items):
- assert len(PythonListModel(items)) == len(items)
-
- def test_pop(self):
- m = PythonListModel([1, 2, 3])
- assert m.pop() == 3
- assert len(m) == 2
- assert m.pop(0) == 1
- assert len(m) == 1
- assert m[0] == 2
-
- def test_append(self):
- m = PythonListModel([])
- m.append(2)
- assert m[0] == 2
- m.append(3)
- assert m[1] == 3
- m.pop()
- m.append(4)
- assert m[1] == 4
-
- def test_extend(self):
- m = PythonListModel([])
- m.extend([2, 3])
- assert m[0] == 2
- assert m[1] == 3
-
- def test_insert(self):
- m = PythonListModel([1, 2, 3])
- m.insert(1, 5)
- assert m[1] == 5
-
- def test_iter(self):
- m = PythonListModel([1, 2, 3])
- assert list(m) == [1, 2, 3]
diff --git a/glue/utils/qt/tests/test_widget_properties.py b/glue/utils/qt/tests/test_widget_properties.py
deleted file mode 100644
index 1bcd87c26..000000000
--- a/glue/utils/qt/tests/test_widget_properties.py
+++ /dev/null
@@ -1,180 +0,0 @@
-import pytest
-
-from qtpy import QtWidgets
-
-from echo.qt.connect import UserDataWrapper
-
-from ..widget_properties import (CurrentComboDataProperty,
- CurrentComboTextProperty,
- CurrentTabProperty,
- TextProperty,
- ButtonProperty,
- FloatLineProperty,
- ValueProperty)
-
-
-def test_combo_data():
-
- class TestClass(object):
-
- co = CurrentComboDataProperty('_combo')
-
- def __init__(self):
- self._combo = QtWidgets.QComboBox()
- self._combo.addItem('a', UserDataWrapper('a'))
- self._combo.addItem('b', UserDataWrapper('b'))
-
- tc = TestClass()
-
- tc.co = 'a'
- assert tc.co == 'a'
- assert tc._combo.currentIndex() == 0
-
- tc.co = 'b'
- assert tc.co == 'b'
- assert tc._combo.currentIndex() == 1
-
- with pytest.raises(ValueError) as exc:
- tc.co = 'c'
- assert exc.value.args[0] == "Cannot find data 'c' in combo box"
-
-
-def test_combo_text():
-
- class TestClass(object):
-
- co = CurrentComboTextProperty('_combo')
-
- def __init__(self):
- self._combo = QtWidgets.QComboBox()
- self._combo.addItem('a')
- self._combo.addItem('b')
-
- tc = TestClass()
-
- tc.co = 'a'
- assert tc.co == 'a'
- assert tc._combo.currentIndex() == 0
-
- tc.co = 'b'
- assert tc.co == 'b'
- assert tc._combo.currentIndex() == 1
-
- with pytest.raises(ValueError) as exc:
- tc.co = 'c'
- assert exc.value.args[0] == "Cannot find text 'c' in combo box"
-
- tc.co = None
- assert tc.co is None
- assert tc._combo.currentIndex() == -1
-
-
-def test_text():
-
- class TestClass(object):
- lab = TextProperty('_label')
-
- def __init__(self):
- self._label = QtWidgets.QLabel()
-
- tc = TestClass()
- tc.lab = 'hello'
- assert tc.lab == 'hello'
- assert tc._label.text() == 'hello'
-
-
-def test_button():
-
- class TestClass(object):
- but = ButtonProperty('_button')
-
- def __init__(self):
- self._button = QtWidgets.QCheckBox()
-
- tc = TestClass()
-
- assert tc.but == tc._button.isChecked()
-
- tc.but = True
- assert tc._button.isChecked()
-
- tc.but = False
- assert not tc._button.isChecked()
-
- tc._button.setChecked(True)
- assert tc.but
-
- tc._button.setChecked(False)
- assert not tc.but
-
-
-def test_float():
-
- class TestClass(object):
- flt = FloatLineProperty('_float')
-
- def __init__(self):
- self._float = QtWidgets.QLineEdit()
-
- tc = TestClass()
-
- tc.flt = 1.0
- assert float(tc._float.text()) == 1.0
-
- tc._float.setText('10')
- assert tc.flt == 10.0
-
- tc._float.setText('')
- assert tc.flt == 0.0
-
-
-def test_value():
-
- class TestClass(object):
- val1 = ValueProperty('_slider')
- val2 = ValueProperty('_slider', value_range=(0, 10))
- val3 = ValueProperty('_slider', value_range=(0.01, 100), log=True)
-
- def __init__(self):
- self._slider = QtWidgets.QSlider()
- self._slider.setMinimum(0)
- self._slider.setMaximum(100)
-
- tc = TestClass()
-
- tc.val1 = 2.0
- assert tc.val1 == 2.0
- assert tc._slider.value() == 2.0
-
- tc.val2 = 3.2
- assert tc.val2 == 3.2
- assert tc._slider.value() == 32
-
- tc.val3 = 10
- assert tc.val3 == 10
- assert tc._slider.value() == 75
-
-
-def test_tab():
-
- class TestClass(object):
- tab = CurrentTabProperty('_tab')
-
- def __init__(self):
- self._tab = QtWidgets.QTabWidget()
- self._tab.addTab(QtWidgets.QWidget(), 'tab1')
- self._tab.addTab(QtWidgets.QWidget(), 'tab2')
-
- tc = TestClass()
-
- tc.tab = 'tab1'
- assert tc.tab == 'tab1'
- assert tc._tab.currentIndex() == 0
-
- tc.tab = 'tab2'
- assert tc.tab == 'tab2'
- assert tc._tab.currentIndex() == 1
-
- with pytest.raises(ValueError) as exc:
- tc.tab = 'tab3'
- assert exc.value.args[0] == "Cannot find value 'tab3' in tabs"
diff --git a/glue/utils/qt/threading.py b/glue/utils/qt/threading.py
index a0dfade82..99e05300c 100644
--- a/glue/utils/qt/threading.py
+++ b/glue/utils/qt/threading.py
@@ -1,45 +1,4 @@
-import sys
-
-from qtpy import QtCore
-
-__all__ = ['Worker']
-
-
-class Worker(QtCore.QThread):
-
- result = QtCore.Signal(object)
- error = QtCore.Signal(object)
-
- def __init__(self, func, *args, **kwargs):
- """
- Execute a function call on a different thread.
-
- Parameters
- ----------
- func : callable
- The function object to call
- args
- Positional arguments to pass to the function
- kwargs
- Keyword arguments to pass to the function
- """
- super(Worker, self).__init__()
- self.func = func
- self.args = args or ()
- self.kwargs = kwargs or {}
-
- def run(self):
- """
- Invoke the function. Upon successful completion, the result signal
- will be fired with the output of the function If an exception
- occurs, the error signal will be fired with the result form
- ``sys.exc_info()``.
- """
- try:
- self.running = True
- result = self.func(*self.args, **self.kwargs)
- self.running = False
- self.result.emit(result)
- except Exception:
- self.running = False
- self.error.emit(sys.exc_info())
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.utils.qt.threading is deprecated, use glue_qt.utils.threading instead', GlueDeprecationWarning)
+from glue_qt.utils.threading import * # noqa
diff --git a/glue/utils/qt/widget_properties.py b/glue/utils/qt/widget_properties.py
index ad3d707d2..6bb8f6b32 100644
--- a/glue/utils/qt/widget_properties.py
+++ b/glue/utils/qt/widget_properties.py
@@ -1,271 +1,4 @@
-"""
-The classes in this module provide a property-like interface
-to widget instance variables in a class. These properties translate
-essential pieces of widget state into more convenient python objects
-(for example, the check state of a button to a bool).
-
-Example Use::
-
- class Foo(object):
- bar = ButtonProperty('_button')
-
- def __init__(self):
- self._button = QtWidgets.QCheckBox()
-
- f = Foo()
- f.bar = True # equivalent to f._button.setChecked(True)
- assert f.bar == True
-"""
-
-import math
-from functools import reduce
-
-from glue.logger import logger
-from glue.utils.array import pretty_number
-
-from echo.qt.connect import _find_combo_data, UserDataWrapper
-
-# Backward-compatibility
-from echo.qt import (connect_checkable_button as connect_bool_button, # noqa
- connect_combo_data as connect_current_combo, # noqa
- connect_combo_text as connect_current_combo_text, # noqa
- connect_float_text as connect_float_edit, # noqa
- connect_value, connect_text) # noqa
-
-connect_int_spin = connect_value
-
-__all__ = ['WidgetProperty', 'CurrentComboDataProperty',
- 'CurrentComboTextProperty', 'CurrentTabProperty', 'TextProperty',
- 'ButtonProperty', 'FloatLineProperty', 'ValueProperty']
-
-
-class WidgetProperty(object):
- """
- Base class for widget properties
-
- Subclasses implement, at a minimum, the "get" and "set" methods,
- which translate between widget states and python variables
-
- Parameters
- ----------
- att : str
- The location, within a class instance, of the widget to wrap around.
- If the widget is nested inside another variable, normal '.' syntax
- can be used (e.g. 'sub_window.button')
- docstring : str, optional
- Optional short summary for the property. Used by sphinx. Should be 1
- sentence or less.
- """
-
- def __init__(self, att, docstring=''):
- self.__doc__ = docstring
- self._att = att.split('.')
-
- def __get__(self, instance, type=None):
- # Under certain circumstances, PyQt will try and access these properties
- # while loading the ui file, so we have to be robust to failures.
- # However, we print out a warning if things fail.
- try:
- widget = reduce(getattr, [instance] + self._att)
- return self.getter(widget)
- except Exception:
- logger.info("An error occured when accessing attribute {0} of {1}. Returning None.".format('.'.join(self._att), instance))
- return None
-
- def __set__(self, instance, value):
- widget = reduce(getattr, [instance] + self._att)
- self.setter(widget, value)
-
- def getter(self, widget):
- """ Return the state of a widget. Depends on type of widget,
- and must be overridden"""
- raise NotImplementedError() # pragma: no cover
-
- def setter(self, widget, value):
- """ Set the state of a widget to a certain value"""
- raise NotImplementedError() # pragma: no cover
-
-
-class CurrentComboDataProperty(WidgetProperty):
- """
- Wrapper around the data in QComboBox.
- """
-
- def getter(self, widget):
- """
- Return the itemData stored in the currently-selected item
- """
- if widget.currentIndex() == -1:
- return None
- else:
- data = widget.itemData(widget.currentIndex())
- if isinstance(data, UserDataWrapper):
- return data.data
- else:
- return data
-
- def setter(self, widget, value):
- """
- Update the currently selected item to the one which stores value in
- its itemData
- """
- # Note, we don't use findData here because it doesn't work
- # well with non-str data
- try:
- idx = _find_combo_data(widget, value)
- except ValueError:
- if value is None:
- idx = -1
- else:
- raise ValueError("Cannot find data '{0}' in combo box".format(value))
- widget.setCurrentIndex(idx)
-
-
-CurrentComboProperty = CurrentComboDataProperty
-
-
-class CurrentComboTextProperty(WidgetProperty):
- """
- Wrapper around the text in QComboBox.
- """
-
- def getter(self, widget):
- """
- Return the itemData stored in the currently-selected item
- """
- if widget.currentIndex() == -1:
- return None
- else:
- return widget.itemText(widget.currentIndex())
-
- def setter(self, widget, value):
- """
- Update the currently selected item to the one which stores value in
- its itemData
- """
- idx = widget.findText(value)
- if idx == -1:
- if value is not None:
- raise ValueError("Cannot find text '{0}' in combo box".format(value))
- widget.setCurrentIndex(idx)
-
-
-class CurrentTabProperty(WidgetProperty):
- """
- Wrapper around QTabWidget.
- """
-
- def getter(self, widget):
- """
- Return the itemData stored in the currently-selected item
- """
- return widget.tabText(widget.currentIndex())
-
- def setter(self, widget, value):
- """
- Update the currently selected item to the one which stores value in
- its itemData
- """
- for idx in range(widget.count()):
- if widget.tabText(idx) == value:
- break
- else:
- raise ValueError("Cannot find value '{0}' in tabs".format(value))
-
- widget.setCurrentIndex(idx)
-
-
-class TextProperty(WidgetProperty):
- """
- Wrapper around the text() and setText() methods for QLabel etc
- """
-
- def getter(self, widget):
- return widget.text()
-
- def setter(self, widget, value):
- widget.setText(value)
- if hasattr(widget, 'editingFinished'):
- widget.editingFinished.emit()
-
-
-class ButtonProperty(WidgetProperty):
- """
- Wrapper around the check state for QAbstractButton widgets
- """
-
- def getter(self, widget):
- return widget.isChecked()
-
- def setter(self, widget, value):
- widget.setChecked(value)
-
-
-class FloatLineProperty(WidgetProperty):
- """
- Wrapper around the text state for QLineEdit widgets.
-
- Assumes that the text is a floating-point number
- """
-
- def getter(self, widget):
- try:
- return float(widget.text())
- except ValueError:
- return 0
-
- def setter(self, widget, value):
- widget.setText(pretty_number(value))
- widget.editingFinished.emit()
-
-
-class ValueProperty(WidgetProperty):
- """
- Wrapper around widgets with value() and setValue()
-
- Parameters
- ----------
- att : str
- The location, within a class instance, of the widget to wrap around.
- If the widget is nested inside another variable, normal '.' syntax
- can be used (e.g. 'sub_window.button')
- docstring : str, optional
- Optional short summary for the property. Used by sphinx. Should be 1
- sentence or less.
- value_range : tuple, optional
- If set, the slider values are mapped to this range.
- log : bool, optional
- If `True`, the mapping is assumed to be logarithmic instead of
- linear.
- """
-
- def __init__(self, att, docstring='', value_range=None, log=False):
- super(ValueProperty, self).__init__(att, docstring=docstring)
-
- if log:
- if value_range is None:
- raise ValueError("log option can only be set if value_range is given")
- else:
- value_range = math.log10(value_range[0]), math.log10(value_range[1])
-
- self.log = log
- self.value_range = value_range
-
- def getter(self, widget):
- val = widget.value()
- if self.value_range is not None:
- imin, imax = widget.minimum(), widget.maximum()
- vmin, vmax = self.value_range
- val = (val - imin) / (imax - imin) * (vmax - vmin) + vmin
- if self.log:
- val = 10 ** val
- return val
-
- def setter(self, widget, val):
- if self.log:
- val = math.log10(val)
- if self.value_range is not None:
- imin, imax = widget.minimum(), widget.maximum()
- vmin, vmax = self.value_range
- val = (val - vmin) / (vmax - vmin) * (imax - imin) + imin
- widget.setValue(int(val))
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.utils.qt.widget_properties is deprecated, use glue_qt.utils.widget_properties instead', GlueDeprecationWarning)
+from glue_qt.utils.widget_properties import * # noqa
diff --git a/glue/utils/tests/test_matplotlib.py b/glue/utils/tests/test_matplotlib.py
index 2631d969a..c2e1d2ef8 100644
--- a/glue/utils/tests/test_matplotlib.py
+++ b/glue/utils/tests/test_matplotlib.py
@@ -7,6 +7,7 @@
from matplotlib.artist import Artist
from numpy.testing import assert_allclose
from matplotlib.backends.backend_agg import FigureCanvasAgg
+from matplotlib.backend_bases import ResizeEvent
from glue.tests.helpers import requires_scipy, requires_skimage
from glue.utils.misc import DeferredMethod
@@ -152,7 +153,8 @@ def test_freeze_margins():
# np.testing.assert_allclose(bbox.x1, 0.9)
# np.testing.assert_allclose(bbox.y1, 0.9)
- fig.canvas.resize_event()
+ resize_event = ResizeEvent("resize_event", fig.canvas)
+ fig.canvas.callbacks.process(resize_event.name, resize_event)
bbox = ax.get_position()
np.testing.assert_allclose(bbox.x0, 0.25)
@@ -161,7 +163,8 @@ def test_freeze_margins():
np.testing.assert_allclose(bbox.y1, 0.75)
fig.set_size_inches(8, 8)
- fig.canvas.resize_event()
+ resize_event = ResizeEvent("resize_event", fig.canvas)
+ fig.canvas.callbacks.process(resize_event.name, resize_event)
bbox = ax.get_position()
np.testing.assert_allclose(bbox.x0, 0.125)
@@ -170,7 +173,8 @@ def test_freeze_margins():
np.testing.assert_allclose(bbox.y1, 0.875)
ax.resizer.margins = [0, 1, 2, 4]
- fig.canvas.resize_event()
+ resize_event = ResizeEvent("resize_event", fig.canvas)
+ fig.canvas.callbacks.process(resize_event.name, resize_event)
bbox = ax.get_position()
np.testing.assert_allclose(bbox.x0, 0.)
diff --git a/glue/viewers/common/qt/__init__.py b/glue/viewers/common/qt/__init__.py
index 678c40862..63c3cdd0c 100644
--- a/glue/viewers/common/qt/__init__.py
+++ b/glue/viewers/common/qt/__init__.py
@@ -1 +1,4 @@
-from . import tools # noqa
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.common.qt is deprecated, use glue_qt.viewers.common instead', GlueDeprecationWarning)
+from glue_qt.viewers.common import * # noqa
diff --git a/glue/viewers/common/qt/base_widget.py b/glue/viewers/common/qt/base_widget.py
index 354c2ad7a..a863189d7 100644
--- a/glue/viewers/common/qt/base_widget.py
+++ b/glue/viewers/common/qt/base_widget.py
@@ -1,241 +1,4 @@
-import os
-
-from qtpy.QtCore import Qt
-from qtpy import QtCore, QtWidgets
-from glue.utils.qt import get_qapp
-from glue.core.qt.mime import LAYERS_MIME_TYPE, LAYER_MIME_TYPE
-
-__all__ = ['BaseQtViewerWidget']
-
-
-class BaseQtViewerWidget(QtWidgets.QMainWindow):
- """
- Base Qt class for all DataViewer widgets. This is not a viewer class in
- itself but is the base widget that should be used for any Qt viewer that
- is to appear inside the MDI area.
- """
-
- window_closed = QtCore.Signal()
- toolbar_added = QtCore.Signal()
-
- _closed = False
-
- def __init__(self, parent=None):
- """
- :type session: :class:`~glue.core.session.Session`
- """
-
- super(BaseQtViewerWidget, self).__init__(parent)
-
- self.setWindowIcon(get_qapp().windowIcon())
-
- status_bar = self.statusBar()
- status_bar.setSizeGripEnabled(False)
- status_bar.setStyleSheet("QStatusBar{font-size:10px}")
-
- self.setFocusPolicy(Qt.StrongFocus)
- self.setAttribute(Qt.WA_DeleteOnClose)
- self.setAcceptDrops(True)
- self.setAnimated(False)
- self.setContentsMargins(2, 2, 2, 2)
-
- self._mdi_wrapper = None # GlueMdiSubWindow that self is embedded in
- self._warn_close = True
-
- def dragEnterEvent(self, event):
- """
- Accept drag-and-drop of data or subset objects.
- """
- if event.mimeData().hasFormat(LAYER_MIME_TYPE):
- event.accept()
- elif event.mimeData().hasFormat(LAYERS_MIME_TYPE):
- event.accept()
- else:
- event.ignore()
-
- def dropEvent(self, event):
- """
- Accept drag-and-drop of data or subset objects.
- """
- if event.mimeData().hasFormat(LAYER_MIME_TYPE):
- self.request_add_layer(event.mimeData().data(LAYER_MIME_TYPE))
-
- assert event.mimeData().hasFormat(LAYERS_MIME_TYPE)
-
- for layer in event.mimeData().data(LAYERS_MIME_TYPE):
- self.request_add_layer(layer)
-
- event.accept()
-
- def mousePressEvent(self, event):
- """
- Consume mouse press events, and prevent them from propagating
- down to the MDI area.
- """
- event.accept()
-
- def close(self, warn=True):
-
- if self._closed:
- return
-
- if warn and not self._confirm_close():
- return
-
- self._warn_close = False
-
- if getattr(self, '_mdi_wrapper', None) is not None:
- self._mdi_wrapper.close()
- self._mdi_wrapper = None
- else:
- try:
- QtWidgets.QMainWindow.close(self)
- except RuntimeError:
- # In some cases the above can raise a "wrapped C/C++ object of
- # type ... has been deleted" error, in which case we can just
- # ignore and carry on.
- pass
-
- self._closed = True
-
- def mdi_wrap(self):
- """
- Wrap this object in a GlueMdiSubWindow
- """
- from glue.app.qt.mdi_area import GlueMdiSubWindow
- sub = GlueMdiSubWindow()
- sub.setWidget(self)
- self.destroyed.connect(sub.close)
- sub.resize(self.size())
- self._mdi_wrapper = sub
- return sub
-
- @property
- def position(self):
- """
- The location of the viewer as a tuple of ``(x, y)``
- """
- target = self._mdi_wrapper or self
- pos = target.pos()
- return pos.x(), pos.y()
-
- @position.setter
- def position(self, xy):
- x, y = xy
- self.move(x, y)
-
- def move(self, x=None, y=None):
- """
- Move the viewer to a new XY pixel location
-
- You can also set the position attribute to a new tuple directly.
-
- Parameters
- ----------
- x : int (optional)
- New x position
- y : int (optional)
- New y position
- """
- x0, y0 = self.position
- if x is None:
- x = x0
- if y is None:
- y = y0
- if self._mdi_wrapper is not None:
- self._mdi_wrapper.move(x, y)
- else:
- QtWidgets.QMainWindow.move(self, x, y)
-
- @property
- def viewer_size(self):
- """
- Size of the viewer as a tuple of ``(width, height)``
- """
- if self._mdi_wrapper is not None:
- sz = self._mdi_wrapper.size()
- else:
- sz = self.size()
- return sz.width(), sz.height()
-
- @viewer_size.setter
- def viewer_size(self, value):
- width, height = value
- if self._mdi_wrapper is None:
- self.resize(width, height)
- else:
- self._mdi_wrapper.resize(width, height)
-
- def closeEvent(self, event):
- """
- Call unregister on window close
- """
-
- if self._warn_close and not self._confirm_close():
- event.ignore()
- return
-
- super(BaseQtViewerWidget, self).closeEvent(event)
- event.accept()
-
- self.window_closed.emit()
-
- def isVisible(self):
- # Override this so as to catch RuntimeError: wrapped C/C++ object of
- # type ... has been deleted
- try:
- return self.isVisible()
- except RuntimeError:
- return False
-
- def _confirm_close(self):
- """Ask for close confirmation
-
- :rtype: bool. True if user wishes to close. False otherwise
- """
- if self._warn_close and not os.environ.get('GLUE_TESTING'):
- buttons = QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel
- dialog = QtWidgets.QMessageBox.warning(self, "Confirm Close",
- "Do you want to close this window?",
- buttons=buttons,
- defaultButton=QtWidgets.QMessageBox.Cancel)
- return dialog == QtWidgets.QMessageBox.Ok
- return True
-
- def layer_view(self):
- return QtWidgets.QWidget()
-
- def options_widget(self):
- return QtWidgets.QWidget()
-
- def set_focus(self, state):
- if state:
- css = """
- DataViewer
- {
- border: 2px solid;
- border-color: rgb(56, 117, 215);
- }
- """
- else:
- css = """
- DataViewer
- {
- border: none;
- }
- """
- self.setStyleSheet(css)
-
- @property
- def window_title(self):
- return str(self)
-
- def update_window_title(self):
- try:
- self.setWindowTitle(self.window_title)
- except RuntimeError: # Avoid C/C++ errors when closing viewer
- pass
-
- def set_status(self, message):
- sb = self.statusBar()
- sb.showMessage(message)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.common.qt.base_widget is deprecated, use glue_qt.viewers.common.base_widget instead', GlueDeprecationWarning)
+from glue_qt.viewers.common.base_widget import * # noqa
diff --git a/glue/viewers/common/qt/contrastlimits.ui b/glue/viewers/common/qt/contrastlimits.ui
deleted file mode 100644
index 3a26c09f0..000000000
--- a/glue/viewers/common/qt/contrastlimits.ui
+++ /dev/null
@@ -1,169 +0,0 @@
-
-
- min_max
-
-
- Qt::WindowModal
-
-
-
- 0
- 0
- 250
- 150
-
-
-
-
- 0
- 0
-
-
-
- Dialog
-
-
- false
-
-
- false
-
-
-
- 3
-
- -
-
-
-
-
-
- 6
-
-
-
-
-
-
- 0
- 35
-
-
-
- Choose Intensity Limits
-
-
- Qt::AlignHCenter|Qt::AlignTop
-
-
-
- -
-
-
-
-
-
-
- 50
- 0
-
-
-
- Low
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Data value to set to black
-
-
- 100
-
-
-
-
-
- -
-
-
-
-
-
-
- 50
- 0
-
-
-
- High
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Data value to set to white
-
-
- 100
-
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
-
-
-
-
-
-
-
- buttonBox
- accepted()
- min_max
- accept()
-
-
- 248
- 254
-
-
- 157
- 274
-
-
-
-
- buttonBox
- rejected()
- min_max
- reject()
-
-
- 316
- 260
-
-
- 286
- 274
-
-
-
-
-
diff --git a/glue/viewers/common/qt/data_slice_widget.py b/glue/viewers/common/qt/data_slice_widget.py
index add7f3999..edad718b0 100644
--- a/glue/viewers/common/qt/data_slice_widget.py
+++ b/glue/viewers/common/qt/data_slice_widget.py
@@ -1,212 +1,4 @@
-import os
-
-import numpy as np
-
-from qtpy import QtCore, QtWidgets
-from glue.utils.qt import load_ui
-from glue.utils import nonpartial, format_minimal
-from glue.icons.qt import get_icon
-from glue.core.state_objects import State, CallbackProperty
-from echo.qt import autoconnect_callbacks_to_qt
-
-
-class SliceState(State):
-
- label = CallbackProperty()
- slider_label = CallbackProperty()
- slider_unit = CallbackProperty()
- slice_center = CallbackProperty()
- use_world = CallbackProperty()
-
-
-class SliceWidget(QtWidgets.QWidget):
-
- slice_changed = QtCore.Signal(int)
-
- def __init__(self, label='', world=None, lo=0, hi=10,
- parent=None, world_unit=None,
- world_warning=False):
-
- super(SliceWidget, self).__init__(parent)
-
- self.state = SliceState()
- self.state.label = label
- self.state.slice_center = (lo + hi) // 2
-
- self._world = np.asarray(world)
- self._world_warning = world_warning
- self._world_unit = world_unit
-
- self.ui = load_ui('data_slice_widget.ui', self,
- directory=os.path.dirname(__file__))
-
- self._connections = autoconnect_callbacks_to_qt(self.state, self.ui)
-
- font = self.text_warning.font()
- font.setPointSize(int(font.pointSize() * 0.75))
- self.text_warning.setFont(font)
-
- self.button_first.setStyleSheet('border: 0px')
- self.button_first.setIcon(get_icon('playback_first'))
- self.button_prev.setStyleSheet('border: 0px')
- self.button_prev.setIcon(get_icon('playback_prev'))
- self.button_back.setStyleSheet('border: 0px')
- self.button_back.setIcon(get_icon('playback_back'))
- self.button_stop.setStyleSheet('border: 0px')
- self.button_stop.setIcon(get_icon('playback_stop'))
- self.button_forw.setStyleSheet('border: 0px')
- self.button_forw.setIcon(get_icon('playback_forw'))
- self.button_next.setStyleSheet('border: 0px')
- self.button_next.setIcon(get_icon('playback_next'))
- self.button_last.setStyleSheet('border: 0px')
- self.button_last.setIcon(get_icon('playback_last'))
-
- self.value_slice_center.setMinimum(lo)
- self.value_slice_center.setMaximum(hi)
- self.value_slice_center.valueChanged.connect(nonpartial(self.set_label_from_slider))
-
- # Figure out the optimal format to use to show the world values. We do
- # this by figuring out the precision needed so that when converted to
- # a string, every string value is different.
-
- if world is not None and len(world) > 1:
- self.label_fmt = format_minimal(world)[0]
- else:
- self.label_fmt = "{:g}"
-
- self.text_slider_label.setMinimumWidth(80)
- self.state.slider_label = self.label_fmt.format(self.value_slice_center.value())
- self.text_slider_label.editingFinished.connect(nonpartial(self.set_slider_from_label))
-
- self._play_timer = QtCore.QTimer()
- self._play_timer.setInterval(500)
- self._play_timer.timeout.connect(nonpartial(self._play_slice))
-
- self.button_first.clicked.connect(nonpartial(self._browse_slice, 'first'))
- self.button_prev.clicked.connect(nonpartial(self._browse_slice, 'prev'))
- self.button_back.clicked.connect(nonpartial(self._adjust_play, 'back'))
- self.button_stop.clicked.connect(nonpartial(self._adjust_play, 'stop'))
- self.button_forw.clicked.connect(nonpartial(self._adjust_play, 'forw'))
- self.button_next.clicked.connect(nonpartial(self._browse_slice, 'next'))
- self.button_last.clicked.connect(nonpartial(self._browse_slice, 'last'))
-
- self.bool_use_world.toggled.connect(nonpartial(self.set_label_from_slider))
-
- if world is None:
- self.state.use_world = False
- self.bool_use_world.hide()
- else:
- self.state.use_world = not world_warning
-
- if world_unit:
- self.state.slider_unit = world_unit
- else:
- self.state.slider_unit = ''
-
- self._play_speed = 0
-
- self.set_label_from_slider()
-
- def set_label_from_slider(self):
- value = self.state.slice_center
- if self.state.use_world:
- value = self._world[value]
- if self._world_warning:
- self.text_warning.show()
- else:
- self.text_warning.hide()
- self.state.slider_unit = self._world_unit
- self.state.slider_label = self.label_fmt.format(value)
- else:
- self.text_warning.hide()
- self.state.slider_unit = ''
- self.state.slider_label = str(value)
-
- def set_slider_from_label(self):
-
- # Ignore recursive calls - we do this rather than ignore_callback
- # below when setting slider_label, otherwise we might be stopping other
- # subscribers to that event from being correctly updated
- if getattr(self, '_in_set_slider_from_label', False):
- return
- else:
- self._in_set_slider_from_label = True
-
- text = self.text_slider_label.text()
- if self.state.use_world:
- # Don't want to assume world is sorted, pick closest value
- value = np.argmin(np.abs(self._world - float(text)))
- self.state.slider_label = self.label_fmt.format(self._world[value])
- else:
- value = int(text)
- self.value_slice_center.setValue(value)
-
- self._in_set_slider_from_label = False
-
- def _adjust_play(self, action):
- if action == 'stop':
- self._play_speed = 0
- elif action == 'back':
- if self._play_speed > 0:
- self._play_speed = -1
- else:
- self._play_speed -= 1
- elif action == 'forw':
- if self._play_speed < 0:
- self._play_speed = +1
- else:
- self._play_speed += 1
- if self._play_speed == 0:
- self._play_timer.stop()
- else:
- self._play_timer.start()
- self._play_timer.setInterval(500 / abs(self._play_speed))
-
- def _play_slice(self):
- if self._play_speed > 0:
- self._browse_slice('next', play=True)
- elif self._play_speed < 0:
- self._browse_slice('prev', play=True)
-
- def _browse_slice(self, action, play=False):
-
- imin = self.value_slice_center.minimum()
- imax = self.value_slice_center.maximum()
- value = self.value_slice_center.value()
-
- # If this was not called from _play_slice, we should stop the
- # animation.
- if not play:
- self._adjust_play('stop')
-
- if action == 'first':
- value = imin
- elif action == 'last':
- value = imax
- elif action == 'prev':
- value = value - 1
- if value < imin:
- value = imax
- elif action == 'next':
- value = value + 1
- if value > imax:
- value = imin
- else:
- raise ValueError("Action should be one of first/prev/next/last")
-
- self.value_slice_center.setValue(value)
-
-
-if __name__ == "__main__":
-
- from glue.utils.qt import get_qapp
-
- app = get_qapp()
-
- widget = SliceWidget(label='BANANA')
- widget.show()
-
- widget = SliceWidget(world=[1, 2, 3, 4, 5, 6, 7], lo=1, hi=7)
- widget.show()
-
- app.exec_()
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.common.qt.data_slice_widget is deprecated, use glue_qt.viewers.common.data_slice_widget instead', GlueDeprecationWarning)
+from glue_qt.viewers.common.data_slice_widget import * # noqa
diff --git a/glue/viewers/common/qt/data_slice_widget.ui b/glue/viewers/common/qt/data_slice_widget.ui
deleted file mode 100644
index c920a6e5a..000000000
--- a/glue/viewers/common/qt/data_slice_widget.ui
+++ /dev/null
@@ -1,268 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 291
- 90
-
-
-
- Form
-
-
-
- 0
-
-
- 0
-
- -
-
-
-
-
-
-
- 75
- true
-
-
-
- Main label
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Show real coordinates
-
-
- true
-
-
- false
-
-
-
-
-
- -
-
-
- color: rgb(255, 33, 28)
-
-
- Warning: real coordinates are not aligned with pixel grid. The coordinate shown above is the value at the center of the slice.
-
-
- Qt::AlignCenter
-
-
- true
-
-
-
- -
-
-
- 10
-
-
-
-
-
- Qt::Horizontal
-
-
-
-
-
- -
-
-
- 2
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Go to first slice
-
-
- <<
-
-
-
- 16
- 16
-
-
-
-
- -
-
-
- Go to previous slice
-
-
- <
-
-
-
- 16
- 16
-
-
-
-
- -
-
-
- Play backwards (click multiple times to speed up)
-
-
- <
-
-
-
- 16
- 16
-
-
-
-
- -
-
-
- Stop the playback
-
-
- â–ª
-
-
-
- 16
- 16
-
-
-
-
- -
-
-
- Play forwards (click multiple times to speed up)
-
-
- >
-
-
-
- 16
- 16
-
-
-
-
- -
-
-
- Go to next slice
-
-
- >
-
-
-
- 16
- 16
-
-
-
- true
-
-
-
- -
-
-
- Go to last slice
-
-
- >>
-
-
-
- 16
- 16
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
- 50
- 16777215
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- TextLabel
-
-
-
-
-
-
-
-
-
-
diff --git a/glue/viewers/common/qt/data_viewer.py b/glue/viewers/common/qt/data_viewer.py
index 001a4ebbb..8e9076d65 100644
--- a/glue/viewers/common/qt/data_viewer.py
+++ b/glue/viewers/common/qt/data_viewer.py
@@ -1,239 +1,4 @@
-from qtpy.QtCore import Qt
-from qtpy import QtWidgets
-from echo import add_callback
-from glue.core.qt.layer_artist_model import QtLayerArtistContainer, LayerArtistWidget
-from glue.utils.qt import set_cursor, messagebox_on_error
-from glue.core.qt.dialogs import warn
-from glue.utils.noconflict import classmaker
-from glue.config import viewer_tool
-from glue.viewers.common.qt.base_widget import BaseQtViewerWidget
-from glue.viewers.common.tool import SimpleToolMenu
-from glue.viewers.common.qt.toolbar import BasicToolbar
-from glue.viewers.common.viewer import Viewer
-from glue.viewers.common.utils import get_viewer_tools
-
-__all__ = ['DataViewer', 'get_viewer_tools']
-
-
-class ToolbarInitializer(object):
- """
- This is a meta-class which ensures that initialize_toolbar is always called
- on DataViewer instances and sub-class instances after all the __init__ code
- has been executed. We need to do this, because often the toolbar can only
- be initialized after everything else (e.g. canvas, etc.) has been set up,
- so we can't do it in DataViewer.__init__.
- """
-
- def __call__(cls, *args, **kwargs):
- obj = type.__call__(cls, *args, **kwargs)
- obj.initialize_toolbar()
- return obj
-
-
-@viewer_tool
-class SaveTool(SimpleToolMenu):
- """
- A generic 'save/export' tool that plugins can register new save/export tools
- with.
-
- To register a new save/export option, add an entry to the viewer
- ``subtools['save']`` list.
- """
- tool_id = 'save'
- icon = 'glue_filesave'
- tool_tip = 'Save/export the plot'
-
-
-# Note: we need to use classmaker here because otherwise we run into issues when
-# trying to use the meta-class with the Qt class.
-class DataViewer(Viewer, BaseQtViewerWidget,
- metaclass=classmaker(left_metas=(ToolbarInitializer,))):
- """
- Base class for all Qt DataViewer widgets.
-
- This defines a minimal interface, and implements the following::
-
- * An automatic call to unregister on window close
- * Drag and drop support for adding data
- """
-
- _layer_artist_container_cls = QtLayerArtistContainer
- _layer_style_widget_cls = None
-
- _toolbar_cls = BasicToolbar
-
- # This defines the mouse mode to be used when no toolbar modes are active
- _default_mouse_mode_cls = None
-
- inherit_tools = True
- tools = ['save', 'window']
- subtools = {
- 'save': [],
- 'window': ['window:movetab', 'window:title']
- }
-
- _close_on_last_layer_removed = True
-
- _options_cls = None
-
- large_data_size = None
-
- def __init__(self, session, state=None, parent=None):
- """
- :type session: :class:`~glue.core.session.Session`
- """
-
- BaseQtViewerWidget.__init__(self, parent)
- Viewer.__init__(self, session, state=state)
-
- self._view = LayerArtistWidget(layer_style_widget_cls=self._layer_style_widget_cls,
- hub=session.hub)
- self._view.layer_list.setModel(self._layer_artist_container.model)
-
- # Set up the options widget, which will include options that control the
- # viewer state
- if self._options_cls is None:
- self.options = QtWidgets.QWidget()
- else:
- self.options = self._options_cls(viewer_state=self.state,
- session=session)
-
- self._tb_vis = {} # store whether toolbars are enabled
- self.toolbar = None
- self._toolbars = []
- self._warn_close = True
-
- # close window when last plot layer deleted
- if self._close_on_last_layer_removed:
- self._layer_artist_container.on_empty(self._close_nowarn)
- self._layer_artist_container.on_changed(self.update_window_title)
-
- add_callback(self.state, 'title', self._on_title_change)
-
- self.update_window_title()
-
- @property
- def selected_layer(self):
- return self._view.layer_list.current_artist()
-
- @set_cursor(Qt.WaitCursor)
- def apply_roi(self, roi):
- pass
-
- def warn(self, message, *args, **kwargs):
- return warn(message, *args, **kwargs)
-
- def _close_nowarn(self):
- return self.close(warn=False)
-
- def closeEvent(self, event):
- super(DataViewer, self).closeEvent(event)
- Viewer.cleanup(self)
- # We tell the toolbar to do cleanup to make sure we get rid of any
- # circular references
- if self.toolbar:
- self.toolbar.cleanup()
-
- def _on_title_change(self, title):
- self.update_window_title()
-
- def layer_view(self):
- return self._view
-
- def addToolBar(self, tb):
- super(DataViewer, self).addToolBar(tb)
- self._toolbars.append(tb)
- self._tb_vis[tb] = True
-
- def remove_toolbar(self, tb):
- self._toolbars.remove(tb)
- self._tb_vis.pop(tb, None)
- super(DataViewer, self).removeToolBar(tb)
-
- def remove_all_toolbars(self):
- for tb in reversed(self._toolbars):
- self.remove_toolbar(tb)
-
- def initialize_toolbar(self):
-
- from glue.config import viewer_tool
-
- self.toolbar = self._toolbar_cls(self, default_mouse_mode_cls=self._default_mouse_mode_cls)
-
- # Need to include tools and subtools declared by parent classes unless
- # specified otherwise
- tool_ids, subtool_ids = get_viewer_tools(self.__class__)
-
- for tool_id in tool_ids:
- mode_cls = viewer_tool.members[tool_id]
- if tool_id in subtool_ids:
- subtools = []
- for subtool_id in subtool_ids[tool_id]:
- subtools.append(viewer_tool.members[subtool_id](self))
- mode = mode_cls(self, subtools=subtools)
- else:
- mode = mode_cls(self)
- self.toolbar.add_tool(mode)
-
- self.addToolBar(self.toolbar)
-
- self.toolbar_added.emit()
-
- def show_toolbars(self):
- """
- Re-enable any toolbars that were hidden with `hide_toolbars()`
-
- Does not re-enable toolbars that were hidden by other means
- """
- for tb in self._toolbars:
- if self._tb_vis.get(tb, False):
- tb.setEnabled(True)
-
- def hide_toolbars(self):
- """
- Disable all the toolbars in the viewer.
-
- This action can be reversed by calling `show_toolbars()`
- """
- for tb in self._toolbars:
- self._tb_vis[tb] = self._tb_vis.get(tb, False) or tb.isVisible()
- tb.setEnabled(False)
-
- def set_focus(self, state):
- super(DataViewer, self).set_focus(state)
- if state:
- self.show_toolbars()
- else:
- self.hide_toolbars()
-
- def __gluestate__(self, context):
- state = Viewer.__gluestate__(self, context)
- state['size'] = self.viewer_size
- state['pos'] = self.position
- state['_protocol'] = 1
- return state
-
- def update_viewer_state(rec, context):
- pass
-
- @classmethod
- def __setgluestate__(cls, rec, context):
-
- if rec.get('_protocol', 0) < 1:
- cls.update_viewer_state(rec, context)
-
- viewer = super(DataViewer, cls).__setgluestate__(rec, context)
-
- viewer.viewer_size = rec['size']
- x, y = rec['pos']
- viewer.move(x=x, y=y)
-
- return viewer
-
- @messagebox_on_error("Failed to add data")
- def add_data(self, data):
- return super(DataViewer, self).add_data(data)
-
- @messagebox_on_error("Failed to add subset")
- def add_subset(self, subset):
- return super(DataViewer, self).add_subset(subset)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.common.qt.data_viewer is deprecated, use glue_qt.viewers.common.data_viewer instead', GlueDeprecationWarning)
+from glue_qt.viewers.common.data_viewer import * # noqa
diff --git a/glue/viewers/common/qt/data_viewer_with_state.py b/glue/viewers/common/qt/data_viewer_with_state.py
index 4d02c0aa5..1e56224d8 100644
--- a/glue/viewers/common/qt/data_viewer_with_state.py
+++ b/glue/viewers/common/qt/data_viewer_with_state.py
@@ -1,7 +1,4 @@
-from glue.viewers.common.qt.data_viewer import DataViewer
-
-__all__ = ['DataViewerWithState']
-
-
-class DataViewerWithState(DataViewer):
- pass
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.common.qt.data_viewer_with_state is deprecated, use glue_qt.viewers.common.data_viewer_with_state instead', GlueDeprecationWarning)
+from glue_qt.viewers.common.data_viewer_with_state import * # noqa
diff --git a/glue/viewers/common/qt/tests/__init__.py b/glue/viewers/common/qt/tests/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/glue/viewers/common/qt/tests/test_data_slice_widget.py b/glue/viewers/common/qt/tests/test_data_slice_widget.py
deleted file mode 100644
index cf5007ee3..000000000
--- a/glue/viewers/common/qt/tests/test_data_slice_widget.py
+++ /dev/null
@@ -1,64 +0,0 @@
-from ..data_slice_widget import SliceWidget
-
-
-class TestSliceWidget(object):
-
- def test_slice_center(self):
- s = SliceWidget(lo=0, hi=10)
- assert s.state.slice_center == 5
-
- def test_browse_slice(self):
- s = SliceWidget(lo=0, hi=10)
- assert s.state.slice_center == 5
- s.button_prev.click()
- assert s.state.slice_center == 4
- s.button_next.click()
- s.button_next.click()
- assert s.state.slice_center == 6
- s.button_first.click()
- assert s.state.slice_center == 0
- s.button_prev.click()
- assert s.state.slice_center == 10
- s.button_next.click()
- assert s.state.slice_center == 0
- s.button_last.click()
- assert s.state.slice_center == 10
- s.button_next.click()
- assert s.state.slice_center == 0
- s.button_prev.click()
- assert s.state.slice_center == 10
- s.button_prev.click()
- assert s.state.slice_center == 9
-
- def test_slice_world(self):
-
- s = SliceWidget(lo=0, hi=5, world=[1, 3, 5, 5.5, 8, 12])
-
- # Check switching between world and pixel coordinates
- s.state.slice_center = 0
- assert s.state.slider_label == '1.0'
- s.state.use_world = False
- assert s.state.slider_label == '0'
- s.state.slice_center = 3
- assert s.state.slider_label == '3'
- s.state.use_world = True
- assert s.state.slider_label == '5.5'
-
- # Round to nearest
- s.state.slider_label = '11'
- assert s.state.slice_center == 5
- assert s.state.slider_label == '12.0'
-
- # Make sure out of bound values work
- s.state.slider_label = '20'
- assert s.state.slice_center == 5
- assert s.state.slider_label == '12.0'
- s.state.slider_label = '-10'
- assert s.state.slice_center == 0
- assert s.state.slider_label == '1.0'
-
- # And disable world and try and set by pixel
- s.state.use_world = False
- s.state.slider_label = '4'
- assert s.state.slice_center == 4
- assert s.state.slider_label == '4'
diff --git a/glue/viewers/common/qt/tests/test_data_viewer.py b/glue/viewers/common/qt/tests/test_data_viewer.py
deleted file mode 100644
index 73fbefb73..000000000
--- a/glue/viewers/common/qt/tests/test_data_viewer.py
+++ /dev/null
@@ -1,134 +0,0 @@
-# pylint: disable=I0011,W0613,W0201,W0212,E1101,E1103
-
-import numpy as np
-from unittest.mock import MagicMock, patch
-
-from glue.core import Data, DataCollection
-from glue.app.qt import GlueApplication
-
-from glue.core.tests.util import simple_session
-from glue.viewers.histogram.qt import HistogramViewer
-from glue.viewers.image.qt import ImageViewer
-from glue.viewers.scatter.qt import ScatterViewer
-from glue.utils.qt import process_events
-
-
-# TODO: We should maybe consider running these tests for all
-# registered Qt viewers.
-
-
-class BaseTestDataViewer(object):
-
- ndim = 1
-
- def test_unregister_on_close(self):
- session = simple_session()
- hub = session.hub
-
- w = self.widget_cls(session)
- w.register_to_hub(hub)
- with patch.object(w, 'unregister') as unregister:
- w.close()
- unregister.assert_called_once_with(hub)
-
- def test_single_draw_call_on_create(self):
- d = Data(x=np.random.random((2,) * self.ndim))
- dc = DataCollection([d])
- app = GlueApplication(dc)
-
- try:
- from glue.viewers.matplotlib.qt.widget import MplCanvas
- draw = MplCanvas.draw
- MplCanvas.draw = MagicMock()
-
- app.new_data_viewer(self.widget_cls, data=d)
-
- # each Canvas instance gives at most 1 draw call
- selfs = [c[0][0] for c in MplCanvas.draw.call_arg_list]
- assert len(set(selfs)) == len(selfs)
- finally:
- MplCanvas.draw = draw
- app.close()
-
- def test_close_on_last_layer_remove(self):
-
- # regression test for 391
-
- d1 = Data(x=np.random.random((2,) * self.ndim))
- d2 = Data(y=np.random.random((2,) * self.ndim))
- dc = DataCollection([d1, d2])
- app = GlueApplication(dc)
- w = app.new_data_viewer(self.widget_cls, data=d1)
- w.add_data(d2)
- process_events()
- assert len(app.viewers[0]) == 1
- dc.remove(d1)
- process_events()
- assert len(app.viewers[0]) == 1
- dc.remove(d2)
- process_events()
- assert len(app.viewers[0]) == 0
- app.close()
-
- def test_viewer_size(self, tmpdir):
-
- # regression test for #781
- # viewers were not restored with the right size
-
- d1 = Data(x=np.random.random((2,) * self.ndim))
- d2 = Data(x=np.random.random((2,) * self.ndim))
- dc = DataCollection([d1, d2])
- app = GlueApplication(dc)
- w = app.new_data_viewer(self.widget_cls, data=d1)
- w.viewer_size = (300, 400)
-
- filename = tmpdir.join('session.glu').strpath
- app.save_session(filename, include_data=True)
-
- app2 = GlueApplication.restore_session(filename)
-
- for viewer in app2.viewers:
- assert viewer[0].viewer_size == (300, 400)
-
- app.close()
- app2.close()
-
- def test_correct_window_title(self):
-
- # check that the viewer is displaying the correct title
-
- d = Data(x=np.random.random((2,) * self.ndim))
- dc = DataCollection([d])
- app = GlueApplication(dc)
- w = app.new_data_viewer(self.widget_cls, data=d)
- w.state.title = "My Viewer"
- assert w.parent().windowTitle() == "My Viewer"
-
- def test_viewer_title_tool(self):
-
- # check that the viewer title tool correctly updates the title
-
- d = Data(x=np.random.random((2,) * self.ndim))
- dc = DataCollection([d])
- app = GlueApplication(dc)
- w = app.new_data_viewer(self.widget_cls, data=d)
-
- tool = w.toolbar.tools["window"].subtools[1]
- with patch('glue.viewers.common.qt.tools.get_text') as gt:
- gt.return_value = "My Viewer"
- tool.activate()
- assert w.state.title == "My Viewer"
- assert w.parent().windowTitle() == "My Viewer"
-
-
-class TestDataViewerScatter(BaseTestDataViewer):
- widget_cls = ScatterViewer
-
-
-class TestDataViewerImage(BaseTestDataViewer):
- ndim = 2
- widget_cls = ImageViewer
-
-
-class TestDataViewerHistogram(BaseTestDataViewer):
- widget_cls = HistogramViewer
diff --git a/glue/viewers/common/qt/tests/test_toolbar.py b/glue/viewers/common/qt/tests/test_toolbar.py
deleted file mode 100644
index b804a1eb6..000000000
--- a/glue/viewers/common/qt/tests/test_toolbar.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# pylint: disable=I0011,W0613,W0201,W0212,E1101,E1103
-
-import pytest
-from glue.config import viewer_tool
-from glue.viewers.common.qt.data_viewer import DataViewer
-from glue.viewers.common.tool import Tool
-from glue.viewers.common.qt.toolbar import BasicToolbar
-from glue.core.tests.util import simple_session
-
-
-@viewer_tool
-class ExampleTool1(Tool):
-
- tool_id = 'TEST1'
- tool_tip = 'tes1'
- icon = 'glue_square'
- shortcut = 'A'
-
-
-@viewer_tool
-class ExampleTool2(Tool):
-
- tool_id = 'TEST2'
- tool_tip = 'tes2'
- icon = 'glue_square'
- shortcut = 'A'
-
-
-class ExampleViewer2(DataViewer):
-
- _toolbar_cls = BasicToolbar
- tools = ['TEST1', 'TEST2']
-
- def __init__(self, session, parent=None):
- super(ExampleViewer2, self).__init__(session, parent=parent)
-
-
-def test_duplicate_shortcut():
- session = simple_session()
- expected_warning = ("Tools 'TEST1' and 'TEST2' have the same "
- r"shortcut \('A'\). Ignoring shortcut for 'TEST2'")
- with pytest.warns(UserWarning, match=expected_warning):
- ExampleViewer2(session)
diff --git a/glue/viewers/common/qt/tool.py b/glue/viewers/common/qt/tool.py
index cd42f2b36..00e222683 100644
--- a/glue/viewers/common/qt/tool.py
+++ b/glue/viewers/common/qt/tool.py
@@ -1,6 +1,4 @@
import warnings
-
-from glue.viewers.common.tool import * # noqa
-
-warnings.warn('glue.viewers.common.qt.tool is deprecated, use '
- 'glue.viewers.common.tool instead', UserWarning)
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.common.qt.tool is deprecated, use glue_qt.viewers.common.tool instead', GlueDeprecationWarning)
+from glue_qt.viewers.common.tool import * # noqa
diff --git a/glue/viewers/common/qt/toolbar.py b/glue/viewers/common/qt/toolbar.py
index e7c51b124..a8024f693 100644
--- a/glue/viewers/common/qt/toolbar.py
+++ b/glue/viewers/common/qt/toolbar.py
@@ -1,216 +1,4 @@
-import os
import warnings
-
-from qtpy import QtCore, QtGui, QtWidgets
-from qtpy.QtCore import Qt
-
-from glue.core.callback_property import add_callback
-from glue.viewers.common.tool import CheckableTool, DropdownTool
-from glue.icons.qt import get_icon
-
-__all__ = ['BasicToolbar']
-
-
-class BasicToolbar(QtWidgets.QToolBar):
-
- tool_activated = QtCore.Signal()
- tool_deactivated = QtCore.Signal()
-
- def __init__(self, parent, default_mouse_mode_cls=None):
- """
- Create a new toolbar object
- """
-
- super(BasicToolbar, self).__init__(parent=parent)
-
- self.actions = {}
- self.tools = {}
- self.setIconSize(QtCore.QSize(25, 25))
- self.layout().setSpacing(1)
- self.setFocusPolicy(Qt.StrongFocus)
- self._active_tool = None
- self._default_mouse_mode_cls = default_mouse_mode_cls
- self._default_mouse_mode = None
- self.setup_default_modes()
-
- def setup_default_modes(self):
- if self._default_mouse_mode_cls is not None:
- self._default_mouse_mode = self._default_mouse_mode_cls(self.parent())
- self._default_mouse_mode.activate()
-
- @property
- def active_tool(self):
- return self._active_tool
-
- @active_tool.setter
- def active_tool(self, new_tool):
-
- if isinstance(new_tool, str):
- if new_tool in self.tools:
- new_tool = self.tools[new_tool]
- else:
- raise ValueError("Unrecognized tool '{0}', should be one of {1}"
- .format(new_tool, ", ".join(sorted(self.tools))))
-
- old_tool = self._active_tool
-
- # If the tool is as before, we don't need to do anything
- if old_tool is new_tool:
- return
-
- # Otheriwse, if the tool changes, then we need to disable the previous
- # tool...
- if old_tool is not None:
- self.deactivate_tool(old_tool)
- if isinstance(old_tool, CheckableTool):
- button = self.actions[old_tool.tool_id]
- if button.isChecked():
- button.blockSignals(True)
- button.setChecked(False)
- button.blockSignals(False)
-
- # We need to then set that no tool is set so that if the next tool
- # opens a viewer that needs to check whether a tool is active, we
- # know that it isn't.
- self._active_tool = None
-
- # ... and enable the new one
- if new_tool is not None:
- self.activate_tool(new_tool)
- if isinstance(new_tool, CheckableTool):
- button = self.actions[new_tool.tool_id]
- if not button.isChecked():
- button.blockSignals(True)
- button.setChecked(True)
- button.blockSignals(False)
-
- if isinstance(new_tool, CheckableTool):
- self._active_tool = new_tool
- self.parent().set_status(new_tool.status_tip)
- self.tool_activated.emit()
- else:
- self.parent().set_status('')
- self.tool_deactivated.emit()
-
- def activate_tool(self, tool):
- if isinstance(tool, CheckableTool) and self._default_mouse_mode is not None:
- self._default_mouse_mode.deactivate()
- tool.activate()
-
- def deactivate_tool(self, tool):
- if isinstance(tool, CheckableTool):
- tool.deactivate()
- if self._default_mouse_mode is not None:
- self._default_mouse_mode.activate()
-
- def _make_action(self, tool, menu=None):
-
- parent = QtWidgets.QToolBar.parent(self)
-
- if isinstance(tool.icon, str):
- if os.path.exists(tool.icon):
- icon = QtGui.QIcon(tool.icon)
- else:
- icon = get_icon(tool.icon)
- else:
- icon = tool.icon
-
- if isinstance(tool, DropdownTool):
- # We use a QToolButton here explicitly so that we can make sure
- # that the whole button opens the pop-up.
- button = QtWidgets.QToolButton()
- if tool.action_text:
- button.setText(tool.action_text)
- if icon:
- button.setIcon(icon)
- button.setPopupMode(button.InstantPopup)
- button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
- action = self.addWidget(button)
- if menu:
- button.setMenu(menu)
- button.clicked.connect(button.showMenu)
- else:
- if icon:
- action = QtWidgets.QAction(icon, tool.action_text, parent)
- else:
- action = QtWidgets.QAction(tool.action_text, parent)
-
- def toggle(checked):
- if checked:
- self.active_tool = tool
- else:
- self.active_tool = None
-
- def trigger():
- self.active_tool = tool
-
- if isinstance(tool, CheckableTool):
- action.toggled.connect(toggle)
- else:
- action.triggered.connect(trigger)
-
- shortcut = None
-
- if tool.shortcut is not None:
-
- # Make sure that the keyboard shortcut is unique
- for m in self.tools.values():
- if tool.shortcut == m.shortcut:
- warnings.warn("Tools '{0}' and '{1}' have the same shortcut "
- "('{2}'). Ignoring shortcut for "
- "'{1}'".format(m.tool_id, tool.tool_id, tool.shortcut))
- break
- else:
- shortcut = tool.shortcut
- action.setShortcut(tool.shortcut)
- action.setShortcutContext(Qt.WidgetShortcut)
-
- if shortcut is None:
- action.setToolTip(tool.tool_tip)
- else:
- action.setToolTip(tool.tool_tip + " [shortcut: {0}]".format(shortcut))
-
- action.setCheckable(isinstance(tool, CheckableTool))
-
- return action
-
- def add_tool(self, tool):
-
- if isinstance(tool, DropdownTool) and len(tool.subtools) > 0:
- menu = QtWidgets.QMenu(self)
- for t in tool.subtools:
- action = self._make_action(t)
- menu.addAction(action)
- elif len(tool.menu_actions()) > 0:
- menu = QtWidgets.QMenu(self)
- for ma in tool.menu_actions():
- ma.setParent(self)
- menu.addAction(ma)
- else:
- menu = None
-
- action = self._make_action(tool, menu=menu)
-
- self.addAction(action)
-
- self.actions[tool.tool_id] = action
-
- # Bind tool visibility to tool.enabled
- def toggle(state):
- action.setVisible(state)
- action.setEnabled(state)
-
- add_callback(tool, 'enabled', toggle)
-
- self.tools[tool.tool_id] = tool
-
- return action
-
- def cleanup(self):
- # We need to make sure we set _default_mouse_mode to None otherwise
- # we keep a reference to the viewer (parent) inside the mouse mode,
- # creating a circular reference.
- if self._default_mouse_mode is not None:
- self._default_mouse_mode.deactivate()
- self._default_mouse_mode = None
- self.active_tool = None
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.common.qt.toolbar is deprecated, use glue_qt.viewers.common.toolbar instead', GlueDeprecationWarning)
+from glue_qt.viewers.common.toolbar import * # noqa
diff --git a/glue/viewers/common/qt/tools.py b/glue/viewers/common/qt/tools.py
index 3408f0457..fcfdba44e 100644
--- a/glue/viewers/common/qt/tools.py
+++ b/glue/viewers/common/qt/tools.py
@@ -1,47 +1,4 @@
-from glue.config import viewer_tool
-from glue.utils.qt import get_text, pick_item
-from glue.viewers.common.tool import Tool, SimpleToolMenu
-
-__all__ = ['MoveTabTool', 'WindowTool']
-
-
-@viewer_tool
-class WindowTool(SimpleToolMenu):
- """
- A generic "window operations" tool that the Qt app and plugins
- can register tools for windowing operations with.
- """
-
- tool_id = 'window'
- icon = 'windows'
- tool_tip = 'Modify the viewer window'
-
-
-@viewer_tool
-class MoveTabTool(Tool):
-
- icon = 'window_tab'
- tool_id = 'window:movetab'
- action_text = 'Move to another tab'
- tool_tip = 'Move viewer to another tab'
-
- def activate(self):
- app = self.viewer.session.application
- default = 1 if (app.tab_count > 1 and app.current_tab == app.tab(0)) else 0
- tab = pick_item(range(app.tab_count), app.tab_names, title="Move Viewer", label="Select a tab", default=default)
- if tab is not None:
- app.move_viewer_to_tab(self.viewer, tab)
-
-
-@viewer_tool
-class ChangeTitleTool(Tool):
-
- icon = 'window_title'
- tool_id = 'window:title'
- action_text = 'Change viewer title'
- tool_tip = 'Change the viewer title'
-
- def activate(self):
- title = get_text(title="Enter a new title")
- if title:
- self.viewer.state.title = title
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.common.qt.tools is deprecated, use glue_qt.viewers.common.tools instead', GlueDeprecationWarning)
+from glue_qt.viewers.common.tools import * # noqa
diff --git a/glue/viewers/custom/helper.py b/glue/viewers/custom/helper.py
index f6e802280..ec089fd78 100644
--- a/glue/viewers/custom/helper.py
+++ b/glue/viewers/custom/helper.py
@@ -71,11 +71,9 @@ def make_selector_func(roi):
but uses the keys as dropdown labels and values as the setting
passed to viewer functions.
* ``keyword='att(foo)'`` doesn't create any widget, but passes
- in the attribute named ``foo`` to the viewer functions, as an
- :class:`~glue.viewers.custom.qt.custom_viewer.AttributeWithInfo` object.
+ in the attribute named ``foo`` to the viewer functions.
* ``keyword='att'`` creates a dropdown to let the user select
- one of the attributes from the data. The selected attribute
- is passed as an :class:`~glue.viewers.custom.qt.custom_viewer.AttributeWithInfo`
+ one of the attributes from the data.
**Viewer Functions**
@@ -96,5 +94,5 @@ def make_selector_func(roi):
"""
# For now we only support Qt, but this function should be extended to work
# with non-Qt front-ends in future.
- from glue.viewers.custom.qt import CustomViewer
+ from glue_qt.viewers.custom import CustomViewer
return CustomViewer.create_new_subclass(name, **kwargs)
diff --git a/glue/viewers/custom/qt/__init__.py b/glue/viewers/custom/qt/__init__.py
index ec4ec3675..b3bf0b8ed 100644
--- a/glue/viewers/custom/qt/__init__.py
+++ b/glue/viewers/custom/qt/__init__.py
@@ -1 +1,4 @@
-from .custom_viewer import * # noqa
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.custom.qt is deprecated, use glue_qt.viewers.custom instead', GlueDeprecationWarning)
+from glue_qt.viewers.custom import * # noqa
diff --git a/glue/viewers/custom/qt/custom_viewer.py b/glue/viewers/custom/qt/custom_viewer.py
index 1910bfba9..07313bde2 100644
--- a/glue/viewers/custom/qt/custom_viewer.py
+++ b/glue/viewers/custom/qt/custom_viewer.py
@@ -1,769 +1,4 @@
-"""
-This module provides utilities for creating custom data viewers. The goal of
-this module is to make it easy for users to make new data viewers by focusing on
-matplotlib visualization logic, and not UI or event processing logic.
-
-The end user typically interacts with this code via :func:`glue.custom_viewer`
-"""
-
-# Implementation notes:
-#
-# Here's a high-level summary of how this code works right now:
-#
-# The user creates a custom viewer using either of the following
-# syntaxes:
-#
-#
-# from glue import custom_viewer
-# my_viewer = custom_viewer('my viewer', checked=True, x='att', ...)
-# @my_viewer.plot_data
-# def plot_data(x, checked, axes):
-# if checked:
-# axes.plot(x)
-# ...
-#
-# or
-#
-# from glue.viewers.custom.qt import CustomViewer
-# class MyViewer(CustomViewer):
-#
-# checked = True
-# x = 'att'
-#
-# def plot_data(self, x, checked, axes):
-# if checked:
-# axes.plot(x)
-#
-# This code has two "magic" features:
-#
-# 1. Attributes like 'checked' and 'x', passed as kwargs to custom_viewer
-# or set as class-level attributes in the subclass, are turned
-# into widgets based on their value
-#
-# 2. Functions like plot_data can take these settings as input (as well
-# as some general purpose arguments like axes). Glue takes care of
-# passing the proper arguments to these functions by introspecting
-# their call signature. Furthermore, it extracts the current
-# value of each setting (ie checked is set to True or False depending
-# on what if the box is checked).
-#
-# The intention of all of this magic is to let a user write "simple" functions
-# to draw custom plots, without having to use Glue or Qt logic directly.
-#
-# Internally, Glue accomlishes this magic as follows:
-#
-# `FormElement`s are created for each attribute in (1). They build the widget
-# and have a method of extracting the current value of the widget
-#
-# Functions like `plot_data` that are designed to be overriden by users
-# are defined as custom descriptors -- when called at the class level,
-# they become decorators that wrap and register the user-defined function.
-# When called at the instance level, they become dispatch functions which
-# deal with the logic in (2). The metaclass deals with registering
-# UDFs when they are overridden in a subclass.
-
-from inspect import getmodule
-from functools import partial
-
-from inspect import getfullargspec
-
-from types import FunctionType, MethodType
-
-import numpy as np
-
-from qtpy.QtWidgets import QWidget, QGridLayout, QLabel
-
-from echo.qt import autoconnect_callbacks_to_qt
-
-from glue.config import qt_client
-
-from glue.core import BaseData
-from glue.core.subset import SubsetState
-from glue.core.data_combo_helper import ComponentIDComboHelper
-from glue.core.component_id import ComponentID
-
-from glue.utils import as_list, all_artists, new_artists, categorical_ndarray, defer_draw
-
-from glue.viewers.matplotlib.qt.data_viewer import MatplotlibDataViewer
-from glue.viewers.matplotlib.state import MatplotlibDataViewerState, MatplotlibLayerState
-from glue.viewers.matplotlib.layer_artist import MatplotlibLayerArtist
-
-from glue.viewers.custom.qt.elements import (FormElement,
- DynamicComponentIDProperty,
- FixedComponentIDProperty)
-
-__all__ = ["AttributeWithInfo", "ViewerUserState", "UserDefinedFunction",
- "CustomViewer", "CustomViewerMeta", "CustomSubsetState",
- "CustomViewer", "CustomLayerArtist", "CustomMatplotlibDataViewer"]
-
-
-class AttributeWithInfo(np.ndarray):
- """
- An array subclass wrapping a Component of a dataset It is an array with the
- following additional attributes: ``id`` contains the ComponentID or string
- name of the Component, and ``categories`` is an array or `None`. For
- categorical Components, it contains the distinct categories which are
- integer-encoded in the AttributeWithInfo
- """
-
- @classmethod
- def make(cls, id, values, categories=None):
- values = np.asarray(values)
- result = values.view(AttributeWithInfo)
- result.id = id
- result.values = values
- result.categories = categories
- return result
-
- @classmethod
- def from_layer(cls, layer, cid, view=None):
- """
- Build an AttributeWithInfo out of a subset or dataset.
-
- Parameters
- ----------
- layer : :class:`~glue.core.data.Data` or :class:`~glue.core.subset.Subset`
- The data to use
- cid : ComponentID
- The ComponentID to use
- view : numpy-style view (optional)
- What slice into the data to use
- """
- values = layer[cid, view]
- if isinstance(values, categorical_ndarray):
- categories = values.categories
- values = values.codes
- else:
- categories = None
- return cls.make(cid, values, categories)
-
- def __gluestate__(self, context):
- return dict(cid=context.id(self.id))
-
- @classmethod
- def __setgluestate__(cls, rec, context):
- return cls.make(context.object(rec['cid']), [], None)
-
-
-class ViewerUserState(object):
- """
- Empty object for users to store data inside.
- """
-
- def __gluestate__(self, context):
- return dict(data=[(k, context.id(v)) for k, v in self.__dict__.items()])
-
- @classmethod
- def __setgluestate__(cls, rec, context):
- result = cls()
- rec = rec['data']
- for k in rec:
- setattr(result, k, context.object(rec[k]))
- return result
-
-
-class UserDefinedFunction(object):
- """
- Descriptor to specify a UserDefinedFunction.
-
- Defined in CustomViewer like this::
-
- class CustomViewer(object):
- ...
- plot_data = UserDefinedFunction('plot_data')
-
- The descriptor gives CustomViewer.plot_data a dual functionality.
- When accessed at the class level, it behaves as a decorator to
- register new UDFs::
-
- cv = custom_viewer(...)
- @cv.plot_data # becomes a decorator
- def plot_data_implementation(...):
- ...
-
- When accessed at the instance level, it becomes a dispatch function
- that calls `plot_data_implementation` with the proper arguments
-
- Alternatively, plot_data_implementation can be specified by explicitly
- overriding plot_data in a subclass. A metaclass takes care of registering
- the UDF in that case, so you can define plot_data as a normal
- (non-decorator, non-descriptor) method.
- """
-
- def __init__(self, name):
- self.name = name
-
- def __get__(self, instance, cls=None):
- if instance is None:
- # accessed from class level, return a decorator
- # to wrap a custom UDF
- return partial(cls._register_override_method, self.name)
-
- # method called at instance level,
- # return a dispatcher to the UDF
- return partial(instance._call_udf, self.name)
-
-
-def introspect_and_call(func, state, override):
- """
- Introspect a function for its arguments, extract values for those
- arguments from a state class, and call the function
-
- Parameters
- ----------
- func : function
- A function to call. It should not define any keywords
- state : State
- A state class containing the values to pass
- override : dict
- A dictionary containing values that should override the state
-
- Returns
- -------
- The result of calling func with the proper arguments
-
- *Example*
-
- def a(x, y):
- return x, y
-
- introspect_and_call(a, state) will return
-
- a(state.x, state.y)
-
- Attributes will be used from ``override`` before ``state``.
- """
-
- a, k = getfullargspec(func)[:2]
-
- args = []
- for item in a:
- if item in override:
- args.append(override[item])
- elif hasattr(state, item):
- args.append(getattr(state, item))
- else:
- setting_list = "\n -".join(state.callback_properties() + list(override))
- raise MissingSettingError("This custom viewer is trying to use an "
- "unrecognized variable named %s\n. Valid "
- "variable names are\n -%s" %
- (item, setting_list))
-
- k = k or {}
-
- return func(*args, **k)
-
-
-class MissingSettingError(KeyError):
- pass
-
-
-class CustomViewerMeta(type):
- """
- Metaclass to construct CustomViewer and subclasses
-
- The metaclass does two things when constructing new
- classes:
-
- - it finds the class-level attributes that describe
- ui elements (eg `checked=False`). It bundles these
- into a `ui` dict attribute, later used to construct
- the FormElements and widgets to represent each setting
- - It creates the qt DataViewer widget class associated with this class.
- - It looks for overridden user-defined methods like `plot_subset`,
- and registers them for later use.
- """
- def __new__(cls, name, bases, attrs):
-
- # don't muck with the base class
- if name == 'CustomViewer':
- return type.__new__(cls, name, bases, attrs)
-
- # Find ui elements
- ui = {}
- for key, value in list(attrs.items()):
- if key.startswith('_') or key in CustomViewer.__dict__:
- continue
- if not isinstance(value, (MethodType, FunctionType)):
- ui[key] = attrs.pop(key)
-
- attrs['ui'] = ui
- attrs.setdefault('name', name)
-
- # collect the user defined functions
-
- udfs = {}
-
- for nm, value in list(attrs.items()):
- dscr = CustomViewer.__dict__.get(nm, None)
-
- if isinstance(dscr, UserDefinedFunction):
- # remove them as class method
- # register them below instead
- udfs[nm] = attrs.pop(nm)
-
- result = type.__new__(cls, name, bases, attrs)
- result._custom_functions = {}
-
- # now wrap the custom user defined functions using the descriptors
- for k, v in udfs.items():
- # register UDF by mimicing the decorator syntax
- udf_decorator = getattr(result, k)
- udf_decorator(v)
-
- result._build_data_viewer()
-
- return result
-
-
-class CustomSubsetState(SubsetState):
- """
- A SubsetState subclass that uses a CustomViewer's "select" function
- """
-
- def __init__(self, coordinator, roi):
- super(CustomSubsetState, self).__init__()
- self._coordinator = coordinator
- self._roi = roi
-
- def to_mask(self, data, view=None):
- return self._coordinator.select(layer=data, roi=self._roi, view=view)
-
- def copy(self):
- return CustomSubsetState(self._coordinator, self._roi)
-
- def __gluestate__(self, context):
- result = {}
- result['viewer'] = context.id(self._coordinator.viewer)
- result['roi'] = context.id(self._roi)
- return result
-
- @classmethod
- def __setgluestate__(cls, rec, context):
- roi = context.object(rec['roi'])
- subset_state = cls(None, roi)
- subset_state._viewer_rec = rec['viewer']
- return subset_state
-
- def __setgluestate_callback__(self, context):
- # When __setgluestate__ is created, the viewers might not yet be
- # deserialized, and these depend on the Data and Subsets existing so
- # we need to deserialize the viewer in a callback so it can be called
- # later on.
- viewer = context.object(self._viewer_rec)
- self._coordinator = viewer._coordinator
- self._viewer_rec = None
-
-
-class BaseCustomOptionsWidget(QWidget):
- """
- Base class for the Qt widget which will be used to show the options.
- """
-
- _widgets = None
-
- def __init__(self, viewer_state=None, session=None):
-
- super(BaseCustomOptionsWidget, self).__init__()
-
- layout = QGridLayout()
- for row, (name, (prefix, viewer_cls)) in enumerate(self._widgets.items()):
- widget = viewer_cls()
- setattr(self, prefix + name, widget)
- layout.addWidget(QLabel(name.capitalize()), row, 0)
- layout.addWidget(widget, row, 1)
- if len(self._widgets) > 0:
- layout.setRowStretch(row + 1, 10)
- self.setLayout(layout)
-
- self.viewer_state = viewer_state
- self.session = session
-
- self._connections = autoconnect_callbacks_to_qt(self.viewer_state, self)
-
-
-class CustomViewer(object, metaclass=CustomViewerMeta):
-
- """
- Base class for custom data viewers.
-
-
- Users can either subclass this class and override
- one or more custom methods listed below, or use the
- :func:`glue.custom_viewer` function and decorate custom
- plot functions.
-
-
- *Custom Plot Methods*
-
- The following methods can be overridden:
-
- - :meth:`CustomViewer.setup`
- - :meth:`CustomViewer.plot_data`
- - :meth:`CustomViewer.plot_subset`
- - :meth:`CustomViewer.settings_changed`
- - :meth:`CustomViewer.make_selector`
- - :meth:`CustomViewer.select`
-
- *Method Signatures*
-
- Custom methods should use argument names from the following list:
-
- - The name of a UI element (e.g. keywords passed to :func:`glue.custom_viewer`,
- or class-level variables in subclasses). The value assigned to this
- argument will be the current UI setting (e.g. booleans for checkboxes).
- - ``axes`` will contain a matplotlib Axes object
- - ``roi`` will contain the ROI a user has drawn (only available for ``make_selector``)
- - ``state`` will contain a general-purpose object to store other data
- - ``style`` contains the :class:`~glue.core.visual.VisualAttributes` describing
- a subset or dataset. Only available for ``plot_data`` and `plot_subset``
- - ``subset`` will contain the relevant :class:`~glue.core.subset.Subset` object.
- Only available for ``plot_subset``
-
-
- *Defining the UI*
-
- Simple widget-based UIs can be specified by providing keywords to :func:`~glue.custom_viewer`
- or class-level variables to subsets. The kind of widget to associate with each
- UI element is determined from it's type.
-
-
- *Example decorator*
-
- ::
-
- v = custom_viewer('Example', checkbox=False)
-
- @v.plot_data
- def plot(checkbox, axes):
- axes.plot([1, 2, 3])
-
- *Example subclass*
-
- ::
-
- class CustomViewerSubset(CustomViewer):
- checkbox = False
-
- def plot_data(self, checkbox, axes):
- axes.plot([1, 2, 3])
-
- The order of arguments can be listed in any order.
- """
-
- # Label to give this widget in the GUI
- name = ''
-
- # Container to hold user descriptions of desired FormElements to create
- ui = {}
-
- # map, e.g., 'plot_data' -> user defined function - we also make sure we
- # override this in sub-classes in CustomViewerMeta
- _custom_functions = {}
-
- def __init__(self, viewer):
- self.viewer = viewer
- self.state = ViewerUserState()
- self.setup()
-
- @property
- def selections_enabled(self):
- return 'make_selector' in self._custom_functions or 'select' in self._custom_functions
-
- @classmethod
- def create_new_subclass(cls, name, **kwargs):
- """
- Convenience method to build a new CustomViewer subclass.
-
- This is used by the custom_viewer function.
-
- Parameters
- ----------
- name : str
- Name of the new viewer
- kwargs
- UI elements in the subclass
- """
- kwargs = kwargs.copy()
- kwargs['name'] = name
- # each subclass needs its own dict
- kwargs['_custom_functions'] = {}
- name = name.replace(' ', '')
- return CustomViewerMeta(name, (CustomViewer,), kwargs)
-
- @classmethod
- def _build_data_viewer(cls):
- """
- Build the DataViewer subclass for this viewer.
- """
-
- # At this point, the metaclass has put all the user options in a dict
- # called .ui, so we go over this dictionary and find the widgets and
- # callback properties for each of them.
-
- widgets = {}
- properties = {}
-
- for name in sorted(cls.ui):
-
- value = cls.ui[name]
- prefix, widget, property = FormElement.auto(value).ui_and_state()
-
- if widget is not None:
- widgets[name] = prefix, widget
-
- properties[name] = property
-
- options_cls = type(cls.__name__ + 'OptionsWidget',
- (BaseCustomOptionsWidget,), {'_widgets': widgets})
-
- state_cls = type(cls.__name__ + 'ViewerState', (CustomMatplotlibViewerState,), properties)
-
- widget_dict = {'LABEL': cls.name,
- 'ui': cls.ui,
- '_options_cls': options_cls,
- '_state_cls': state_cls,
- '_coordinator_cls': cls}
-
- viewer_cls = type(cls.__name__ + 'DataViewer',
- (CustomMatplotlibDataViewer,),
- widget_dict)
-
- cls._viewer_cls = viewer_cls
- qt_client.add(viewer_cls)
-
- # add new classes to module namespace
- # needed for proper state saving/restoring
- for c in [viewer_cls, cls]:
- mod = getmodule(ViewerUserState)
- w = getattr(mod, c.__name__, None)
- if w is not None:
- raise RuntimeError("Duplicate custom viewer detected %s" % c)
- setattr(mod, c.__name__, c)
- c.__module__ = mod.__name__
-
- @classmethod
- def _register_override_method(cls, name, func):
- """
- Register a new custom method like "plot_data"
-
- Users need not call this directly - it is called when a method is
- overridden or decorated
- """
- cls._custom_functions[name] = func
-
- def _build_subset_state(self, roi):
-
- if 'make_selector' in self._custom_functions:
- return self.make_selector(roi=roi)
-
- if 'select' in self._custom_functions:
- return CustomSubsetState(self, roi)
-
- raise RuntimeError("Selection not supported for this viewer.")
-
- # List of user-defined functions.
- # Users can either use these as decorators to
- # wrap custom functions, or override them in subclasses.
-
- setup = UserDefinedFunction('setup')
- """
- Custom method called when plot is created
- """
-
- plot_subset = UserDefinedFunction('plot_subset')
- """
- Custom method called to show a subset
- """
-
- plot_data = UserDefinedFunction('plot_data')
- """
- Custom method called to show a dataset
- """
-
- make_selector = UserDefinedFunction('make_selector')
- """
- Custom method called to build a :class:`~glue.core.subset.SubsetState` from an ROI.
-
- See :meth:`~CustomViewer.select` for an alternative way to define selections,
- by returning Boolean arrays instead of SubsetStates.
-
- Functions have access to the roi by accepting an ``roi``
- argument to this function
- """
-
- settings_changed = UserDefinedFunction('settings_changed')
- """
- Custom method called when UI settings change.
- """
-
- select = UserDefinedFunction('select')
- """
- Custom method called to filter data using an ROI.
-
- This is an alternative function to :meth:`~CustomViewer.make_selector`,
- which returns a numpy boolean array instead of a SubsetState.
-
- Functions have access to the roi by accepting an ``roi``
- argument to this function
- """
-
- def _call_udf(self, method_name, **kwargs):
- """
- Call a user-defined function stored in the _custom_functions dict
-
- Parameters
- ----------
- method_name : str
- The name of the user-defined method to setup a dispatch for
- use_cid : bool, optional
- Whether to pass component IDs to the user function instead of the
- data itself.
- **kwargs : dict
- Custom settings to pass to the UDF if they are requested by name
- as input arguments
-
- Returns
- -------
- The result of the UDF
-
- Notes
- -----
- This function builds the necessary arguments to the
- user-defined function. It also attempts to monitor
- the state of the matplotlib plot, removing stale
- artists and re-rendering the canvas as needed.
- """
-
- # get the custom function
- try:
- func = self._custom_functions[method_name]
- except KeyError:
- return []
-
- override = kwargs.copy()
-
- if 'layer' not in override and len(self.viewer.state.layers) > 0:
- override['layer'] = self.viewer.state.layers[0].layer
-
- if 'layer' in override:
-
- override.setdefault('style', override['layer'].style)
-
- # Dereference attributes
- for name, property in self.viewer.state.iter_callback_properties():
- value = getattr(self.viewer.state, name)
- if isinstance(value, ComponentID) or isinstance(property, FixedComponentIDProperty):
- override[name] = AttributeWithInfo.from_layer(override['layer'], value, view=override.get('view', None))
-
- # add some extra information that the user might want
- override.setdefault('self', self)
- override.setdefault('axes', self.viewer.axes)
- override.setdefault('figure', self.viewer.axes.figure)
- override.setdefault('state', self.state)
-
- # call method, keep track of newly-added artists
- result = introspect_and_call(func, self.viewer.state, override)
-
- self.viewer.redraw()
-
- return result
-
-
-class CustomLayerArtist(MatplotlibLayerArtist):
- """
- LayerArtist for simple custom viewers that use Matplotlib
- """
-
- _layer_state_cls = MatplotlibLayerState
-
- def __init__(self, coordinator, *args, **kwargs):
- super(CustomLayerArtist, self).__init__(*args, **kwargs)
- self._coordinator = coordinator
- self.state.add_global_callback(self.update)
- self._viewer_state.add_global_callback(self.update)
-
- def update(self, *args, **kwargs):
-
- if not self._visible:
- return
-
- self.clear()
-
- old = all_artists(self.axes.figure)
-
- if isinstance(self.state.layer, BaseData):
- a = self._coordinator.plot_data(layer=self.state.layer)
- else:
- a = self._coordinator.plot_subset(layer=self.state.layer, subset=self.state.layer)
-
- # if user explicitly returns the newly-created artists,
- # then use them. Otherwise, introspect to find the new artists
- if a is None:
- self.mpl_artists = list(new_artists(self.axes.figure, old))
- else:
- self.mpl_artists = as_list(a)
-
- for a in self.mpl_artists:
- a.set_zorder(self.state.zorder)
-
-
-class CustomMatplotlibDataViewer(MatplotlibDataViewer):
- """
- Base Qt widget class for simple custom viewers that use Matplotlib
- """
-
- LABEL = ''
- tools = ['select:rectangle', 'select:polygon']
-
- _state_cls = None
- _options_cls = None
- _layer_style_viewer_cls = None
- _data_artist_cls = CustomLayerArtist
- _subset_artist_cls = CustomLayerArtist
-
- _coordinator_cls = None
-
- def __init__(self, session, parent=None, **kwargs):
- super(CustomMatplotlibDataViewer, self).__init__(session, parent, **kwargs)
- self._coordinator = self._coordinator_cls(self)
- self.state.add_global_callback(self._on_state_change)
- self._on_state_change()
-
- def _on_state_change(self, *args, **kwargs):
- self._coordinator.settings_changed()
-
- def get_layer_artist(self, cls, layer=None, layer_state=None):
- return cls(self._coordinator, self.axes, self.state, layer=layer, layer_state=layer_state)
-
- @defer_draw
- def apply_roi(self, roi):
-
- # Force redraw to get rid of ROI. We do this because applying the
- # subset state below might end up not having an effect on the viewer,
- # for example there may not be any layers, or the active subset may not
- # be one of the layers. So we just explicitly redraw here to make sure
- # a redraw will happen after this method is called.
- self.redraw()
-
- if len(self.layers) == 0:
- return
-
- subset_state = self._coordinator._build_subset_state(roi=roi)
- self.apply_subset_state(subset_state)
-
-
-class CustomMatplotlibViewerState(MatplotlibDataViewerState):
-
- def __init__(self, *args, **kwargs):
- super(CustomMatplotlibViewerState, self).__init__(*args)
- self._cid_helpers = []
- for name, property in self.iter_callback_properties():
- if isinstance(property, DynamicComponentIDProperty):
- self._cid_helpers.append(ComponentIDComboHelper(self, name))
- self.add_callback('layers', self._on_layer_change)
- self.update_from_dict(kwargs)
-
- def _on_layer_change(self, *args):
- for helper in self._cid_helpers:
- helper.set_multiple_data(self.layers_data)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.custom.qt.custom_viewer is deprecated, use glue_qt.viewers.custom.custom_viewer instead', GlueDeprecationWarning)
+from glue_qt.viewers.custom.custom_viewer import * # noqa
diff --git a/glue/viewers/custom/qt/elements.py b/glue/viewers/custom/qt/elements.py
index 5b3d71641..1c2d688c9 100644
--- a/glue/viewers/custom/qt/elements.py
+++ b/glue/viewers/custom/qt/elements.py
@@ -1,288 +1,4 @@
-from echo import CallbackProperty, SelectionCallbackProperty
-
-from qtpy.QtWidgets import (QSlider, QLineEdit, QComboBox, QWidget,
- QLabel, QHBoxLayout, QCheckBox)
-from qtpy.QtCore import Qt
-
-__all__ = ["FormElement", "NumberElement", "TextBoxElement", "FloatElement",
- "BoolElement", "ChoiceElement", "FixedComponentIDProperty",
- "FixedComponentElement", "ComponenentElement", "DynamicComponentIDProperty"]
-
-
-class QLabeledSlider(QWidget):
- """
- A labeled slider widget
- """
-
- range = None
- integer = None
-
- def __init__(self, parent=None):
-
- super(QLabeledSlider, self).__init__(parent)
-
- self._range = range
-
- self._slider = QSlider()
- self._slider.setMinimum(0)
- self._slider.setMaximum(100)
- self._slider.setOrientation(Qt.Horizontal)
-
- self._label = QLabel('')
- self._layout = QHBoxLayout()
- self._layout.setContentsMargins(2, 2, 2, 2)
- self._layout.addWidget(self._slider)
- self._layout.addWidget(self._label)
-
- self._slider.valueChanged.connect(self._update_label)
-
- self.setLayout(self._layout)
-
- def _update_label(self, *args):
- self._label.setText(str(self.value()))
-
- @property
- def valueChanged(self):
- return self._slider.valueChanged
-
- def value(self, layer=None, view=None):
- value = self._slider.value() / 100. * (self.range[1] - self.range[0]) + self.range[0]
- if self.integer:
- return int(value)
- else:
- return value
-
- _in_set_value = False
-
- def setValue(self, value):
- if self._in_set_value:
- return
- self._in_set_value = True
- value = int(100 * (value - self.range[0]) / (self.range[1] - self.range[0]))
- self._slider.setValue(value)
- self._in_set_value = False
-
-
-class FormElement(object):
-
- """
- Base class for user-defined settings in a custom widget.
-
- Each form element has a value() and a widget. Subclasses
- must override _build_ui, value, and recognizes. They
- may override register_to_hub and add_data.
- """
-
- def __init__(self, params):
- self.params = params
-
- @classmethod
- def recognizes(cls, params):
- """
- Returns whether or not a shorthand "params" object
- can be passed to __init__ to construct an element
- """
- raise NotImplementedError
-
- def ui_and_state(self):
- """
- Build and return a widget to represent this setting.
- """
- raise NotImplementedError()
-
- @staticmethod
- def auto(params):
- """
- Construct the appropriate FormElement subclass,
- given a shorthand object. For examle,
- FormElement.auto((0., 1.)) returns a NumberElement
- """
-
- def subclasses(cls):
- return cls.__subclasses__() + [g for s in cls.__subclasses__() for g in subclasses(s)]
-
- for cls in subclasses(FormElement):
- if cls.recognizes(params):
- return cls(params)
- raise ValueError("Unrecognzied UI Component: %s" % (params,))
-
-
-class NumberElement(FormElement):
-
- """
- A form element representing a number
-
- The shorthand is a tuple of 2 or 3 numbers:
- (min, max) or (min, max default)::
-
- e = FormElement.auto((0., 1.))
- """
-
- @classmethod
- def recognizes(cls, params):
- try:
- if len(params) not in [2, 3]:
- return False
- return all(isinstance(p, (int, float)) for p in params)
- except TypeError:
- return False
-
- def ui_and_state(self):
-
- if len(self.params) == 3:
- default = self.params[2]
- else:
- default = 0.5 * (self.params[0] + self.params[1])
-
- # We can't initialize QLabeledSlider yet because this could get called
- # before the Qt application has been initialized. So for now we just make
- # a subclass of QLabeledSlider with the range we need
- class CustomSlider(QLabeledSlider):
- range = self.params[:2]
- integer = isinstance(self.params[0], int) and isinstance(self.params[1], int)
-
- return 'value_', CustomSlider, CallbackProperty(default)
-
-
-class TextBoxElement(FormElement):
- """
- A form element representing a generic textbox
-
- The shorthand is any string starting with an _.::
-
- e = FormElement.auto("_default")
-
- Everything after the underscore is taken as the default value.
- """
-
- @classmethod
- def recognizes(cls, params):
- try:
- if isinstance(params, str) & params.startswith('_'):
- return True
- except AttributeError:
- return None
-
- def ui_and_state(self):
- default = self.params[1:]
- return 'text_', QLineEdit, CallbackProperty(default)
-
-
-class FloatElement(FormElement):
- """
- A form element representing a generic number box.
-
- The shorthand is any number::
-
- e = FormElement.auto(2)
-
- The number itself is taken as the default value.
- """
-
- @classmethod
- def recognizes(cls, params):
- return isinstance(params, (int, float)) and not isinstance(params, bool)
-
- def ui_and_state(self):
- default = self.params
- return 'valuetext_', QLineEdit, CallbackProperty(default)
-
-
-class BoolElement(FormElement):
-
- """
- A checkbox representing a boolean setting
-
- The shorthand notation is True or False::
-
- e = FormElement.auto(False)
- """
-
- @classmethod
- def recognizes(cls, params):
- return isinstance(params, bool)
-
- def ui_and_state(self):
- default = self.params
- return 'bool_', QCheckBox, CallbackProperty(default)
-
-
-class ChoiceElement(FormElement):
-
- """
- A dropdown selector to choose between a set of items
-
- Shorthand notation is a sequence of strings or a dict::
-
- e = FormElement.auto({'a':1, 'b':2})
- e = FormElement.auto(['a', 'b', 'c'])
- """
-
- @classmethod
- def recognizes(cls, params):
- if isinstance(params, str):
- return False
- try:
- return all(isinstance(p, str) for p in params)
- except TypeError:
- return False
-
- def ui_and_state(self):
- if isinstance(self.params, list):
- choices = self.params
- display_func = None
- else:
- params_inv = dict((value, key) for key, value in self.params.items())
- choices = list(params_inv.keys())
- display_func = params_inv.get
- property = SelectionCallbackProperty(default_index=0, choices=choices,
- display_func=display_func)
- return 'combosel_', QComboBox, property
-
-
-class FixedComponentIDProperty(CallbackProperty):
- pass
-
-
-class FixedComponentElement(FormElement):
-
- """
- An element for a Data Component. Does not have a widget
-
- The shorthand notation is 'att(comp_name)'::
-
- e = FormElement.auto('att(foo)')
- """
-
- @classmethod
- def recognizes(cls, params):
- try:
- return params.startswith('att(')
- except AttributeError:
- return False
-
- def ui_and_state(self):
- component_name = self.params.split('(')[-1][:-1]
- return None, None, FixedComponentIDProperty(component_name)
-
-
-class DynamicComponentIDProperty(SelectionCallbackProperty):
- pass
-
-
-class ComponenentElement(FormElement):
-
- """
- A dropdown selector to choose a component
-
- The shorthand notation is 'att'::
-
- e = FormElement.auto('att')
- """
-
- @classmethod
- def recognizes(cls, params):
- return params == 'att'
-
- def ui_and_state(self):
- return 'combosel_', QComboBox, DynamicComponentIDProperty()
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.custom.qt.elements is deprecated, use glue_qt.viewers.custom.elements instead', GlueDeprecationWarning)
+from glue_qt.viewers.custom.elements import * # noqa
diff --git a/glue/viewers/custom/qt/tests/__init__.py b/glue/viewers/custom/qt/tests/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/glue/viewers/custom/qt/tests/test_custom_viewer.py b/glue/viewers/custom/qt/tests/test_custom_viewer.py
deleted file mode 100644
index e40e5fb22..000000000
--- a/glue/viewers/custom/qt/tests/test_custom_viewer.py
+++ /dev/null
@@ -1,339 +0,0 @@
-from collections import OrderedDict
-
-import numpy as np
-from matplotlib.axes import Axes
-from unittest.mock import MagicMock
-from numpy.testing import assert_array_equal
-
-from glue.core.tests.test_state import clone
-from glue.core.tests.util import simple_session
-from glue.core.subset import SubsetState
-from glue.core import Data
-from glue import custom_viewer
-
-from glue.app.qt import GlueApplication
-from glue.app.qt.tests.test_application import check_clone_app
-from ..custom_viewer import CustomViewer, CustomSubsetState, AttributeWithInfo
-
-
-def _make_widget(viewer):
- s = simple_session()
- return viewer._viewer_cls(s)
-
-
-viewer = custom_viewer('Testing Custom Viewer',
- a=(0, 100),
- b='att',
- c='att(x)',
- d=True,
- e=False,
- f=['a', 'b', 'c'],
- g=OrderedDict(a=1, b=2, c=3),
- h=64
- )
-
-
-setup = MagicMock()
-settings_changed = MagicMock()
-plot_subset = MagicMock()
-plot_data = MagicMock()
-make_selector = MagicMock()
-make_selector.return_value = MagicMock(spec=SubsetState)
-make_selector().copy.return_value = MagicMock(spec=SubsetState)
-make_selector().copy().to_mask.return_value = np.array([False, True, True])
-
-
-@viewer.setup
-def _setup(axes):
- setup(axes)
-
-
-@viewer.plot_data
-def _plot_data(axes, a, b, g, h):
- plot_data(axes=axes, a=a, b=b, g=g, h=h)
- return []
-
-
-@viewer.plot_subset
-def _plot_subset(b, c, d, e, f, style):
- plot_subset(b=b, c=c, d=d, e=e, f=f, style=style)
- return []
-
-
-@viewer.settings_changed
-def _settings_changed(state):
- settings_changed(state=state)
-
-
-@viewer.make_selector
-def _make_selector(roi, c):
- make_selector(roi=roi, c=c)
- return SubsetState()
-
-
-def test_custom_classes_dont_share_methods():
- """Regression test for #479"""
- a = custom_viewer('a')
- b = custom_viewer('b')
- assert a._custom_functions is not b._custom_functions
-
-
-class ViewerSubclass(CustomViewer):
- a = (0, 100)
- b = 'att'
- c = 'att(x)'
- d = True
- e = False
- f = ['a', 'b', 'c']
- g = OrderedDict(a=1, b=2, c=3)
- h = 64
-
- def setup(self, axes):
- return setup(axes)
-
- def plot_data(self, axes, a, b, g, h):
- return plot_data(axes=axes, a=a, b=b, g=g, h=h)
-
- def plot_subset(self, b, c, d, e, f, style):
- return plot_subset(b=b, c=c, d=d, e=e, f=f, style=style)
-
- def settings_changed(self, state):
- return settings_changed(state=state)
-
- def make_selector(self, roi, c):
- return make_selector(roi=roi, c=c)
-
-
-class TestCustomViewer(object):
-
- def setup_class(self):
- self.viewer = viewer
-
- def setup_method(self, method):
- setup.reset_mock()
- settings_changed.reset_mock()
- plot_subset.reset_mock()
- plot_data.reset_mock()
- make_selector.reset_mock()
-
- self.data = Data(x=[1, 2, 3], y=[2, 3, 4])
- self.session = simple_session()
- self.dc = self.session.data_collection
- self.dc.append(self.data)
-
- def teardown_method(self, method):
- if hasattr(self, 'w'):
- self.w.unregister(self.session.hub)
-
- def build(self):
- w = self.viewer._viewer_cls(self.session)
- w.register_to_hub(self.session.hub)
- self.w = w
- return w
-
- def test_setup_called_on_init(self):
- ct = setup.call_count
- self.build()
- assert setup.call_count == ct + 1
-
- def test_separate_widgets_have_separate_state(self):
- w1 = self.build()
- w2 = self.build()
-
- assert w1._coordinator is not w2._coordinator
- assert w1._coordinator.state is not w2._coordinator.state
-
- def test_plot_data(self):
- w = self.build()
- w.add_data(self.data)
-
- a, k = plot_data.call_args
- assert isinstance(k['axes'], Axes)
- assert set(k.keys()) == set(('axes', 'a', 'b', 'g', 'h'))
- assert k['a'] == 50
- assert k['g'] == 1
- assert k['h'] == 64
-
- def test_plot_subset(self):
- w = self.build()
- w.add_data(self.data)
-
- self.dc.new_subset_group(subset_state=self.data.id['x'] > 2)
-
- a, k = plot_subset.call_args
- assert set(k.keys()) == set(('b', 'c', 'd', 'e', 'f', 'style'))
-
- assert_array_equal(k['b'], [3])
- assert_array_equal(k['c'], [3])
- assert k['d']
- assert not k['e']
- assert k['f'] == 'a'
-
- def test_make_selector(self):
- w = self.build()
- w.add_data(self.data)
- roi = MagicMock()
- w.apply_roi(roi)
-
- a, k = make_selector.call_args
-
- assert set(k.keys()) == set(('roi', 'c'))
- assert k['roi'] is roi
-
- def test_settings_change(self):
- w = self.build()
- ct = settings_changed.call_count
- w.options_widget().bool_d.setChecked(False)
- assert settings_changed.call_count == ct + 1
- a, k = settings_changed.call_args
- assert 'state' in k
-
- def test_component_autoupdate(self):
-
- w = self.build()
- w.add_data(self.data)
-
- assert w.options_widget().combosel_b.count() == 2
- self.data.add_component([10, 20, 30], label='c')
- assert w.options_widget().combosel_b.count() == 3
-
- def test_settings_changed_called_on_init(self):
- self.build()
- assert settings_changed.call_count == 1
-
- def test_selections_enabled(self):
- w = self.build()
- assert w._coordinator.selections_enabled
- assert 'select:rectangle' in w.toolbar.tools
- assert 'select:polygon' in w.toolbar.tools
-
-
-def test_state_save():
- app = GlueApplication()
- w = app.new_data_viewer(viewer._viewer_cls) # noqa
- check_clone_app(app)
-
-
-def test_state_save_with_data_layers():
- app = GlueApplication()
- dc = app.data_collection
- d = Data(x=[1, 2, 3], label='test')
- dc.append(d)
- w = app.new_data_viewer(viewer._viewer_cls)
- w.add_data(d)
- check_clone_app(app)
-
-
-class TestCustomSelectMethod(object):
-
- def setup_class(self):
- self.viewer = custom_viewer('CustomSelectViewer',
- x='att(x)', flip=False)
-
- @self.viewer.select
- def select(roi, x, flip):
- if flip:
- return x <= 1
- return x > 1
-
- def setup_method(self, method):
- self.data = Data(x=[1, 2, 3], y=[2, 3, 4])
- self.session = simple_session()
- self.dc = self.session.data_collection
- self.dc.append(self.data)
-
- def build(self):
- return self.viewer._viewer_cls(self.session)
-
- def test_subset_state(self):
- w = self.build()
- v = w._coordinator
- roi = MagicMock()
- s = CustomSubsetState(v, roi)
- assert_array_equal(s.to_mask(self.data), [False, True, True])
-
- def test_subset_state_view(self):
- w = self.build()
- v = w._coordinator
- roi = MagicMock()
- s = CustomSubsetState(v, roi)
- assert_array_equal(s.to_mask(self.data, view=slice(None, None, 2)),
- [False, True])
-
- def test_settings_frozen_at_creation(self):
- w = self.build()
- v = w._coordinator
- roi = MagicMock()
- s = CustomSubsetState(v, roi)
- w.flip = True
- assert_array_equal(s.to_mask(self.data), [False, True, True])
-
- def test_save_load(self):
- app = GlueApplication(session=self.session)
- w = app.new_data_viewer(self.viewer._viewer_cls)
- v = w._coordinator
- roi = None
- s = CustomSubsetState(v, roi)
- app.data_collection.new_subset_group(subset_state=s, label='test')
- app2 = clone(app)
- s2 = app2.data_collection[0].subsets[0].subset_state
- assert_array_equal(s2.to_mask(self.data), [False, True, True])
-
-
-class TestCustomViewerSubclassForm(TestCustomViewer):
-
- def setup_class(self):
- self.viewer = ViewerSubclass
-
-
-class TestAttributeWithInfo(object):
-
- def setup_method(self, method):
- d = Data(x=[1, 2, 3, 4, 5], c=['a', 'b', 'a', 'a', 'b'], label='test')
- s = d.new_subset()
- s.subset_state = d.id['x'] > 2
- self.d = d
- self.s = s
-
- def test_numerical(self):
- v = AttributeWithInfo.from_layer(self.d, self.d.id['x'])
- assert_array_equal(v, [1, 2, 3, 4, 5])
- assert v.id == self.d.id['x']
- assert v.categories is None
-
- def test_categorical(self):
- v = AttributeWithInfo.from_layer(self.d, self.d.id['c'])
- assert_array_equal(v, [0, 1, 0, 0, 1])
- assert v.id == self.d.id['c']
- assert_array_equal(v.categories, ['a', 'b'])
-
- def test_subset(self):
- v = AttributeWithInfo.from_layer(self.s, self.d.id['x'])
- assert_array_equal(v, [3, 4, 5])
- assert v.id == self.d.id['x']
- assert v.categories is None
-
-
-def test_two_custom_viewer_classes():
-
- class MyWidget1(CustomViewer):
-
- text_box1_Widget1 = '_Hello'
-
- def setup(self, text_box1_Widget1):
- pass
-
- class MyWidget2(CustomViewer):
-
- text_box1_Widget2 = '_Hello'
- text_box2_Widget2 = '_world'
-
- def setup(self, text_box1_Widget2, text_box2_Widget2):
- pass
-
- app = GlueApplication()
- dc = app.data_collection
- d = Data(x=[1, 2, 3], label='test')
- dc.append(d)
- app.new_data_viewer(MyWidget1._viewer_cls)
- app.new_data_viewer(MyWidget2._viewer_cls)
diff --git a/glue/viewers/custom/qt/tests/test_elements.py b/glue/viewers/custom/qt/tests/test_elements.py
deleted file mode 100644
index 076644d85..000000000
--- a/glue/viewers/custom/qt/tests/test_elements.py
+++ /dev/null
@@ -1,66 +0,0 @@
-import pytest
-
-from glue.core.state_objects import State
-from ..elements import (FormElement, NumberElement, ChoiceElement,
- FloatElement, TextBoxElement)
-
-
-def get_value(element):
-
- prefix, widget_cls, property = element.ui_and_state()
-
- class TemporaryState(State):
- a = property
-
- temp = TemporaryState()
- return temp.a
-
-
-class TestFormElements(object):
-
- def test_number_default_value(self):
- e = FormElement.auto((0, 100, 30))
- assert get_value(e) == 30
-
- def test_number_float(self):
- e = FormElement.auto((0.0, 1.0, 0.3))
- assert get_value(e) == 0.3
-
- def test_number_list(self):
- e = FormElement.auto([0, 10])
- assert isinstance(e, NumberElement)
-
- def test_choice_list(self):
- e = FormElement.auto(['a', 'b'])
- assert isinstance(e, ChoiceElement)
-
- def test_choice_tuple(self):
- e = FormElement.auto(('a', 'b'))
- assert isinstance(e, ChoiceElement)
-
- def test_float(self):
- e = FormElement.auto(1.2)
- assert isinstance(e, FloatElement)
-
- e = FormElement.auto(2)
- assert isinstance(e, FloatElement)
- assert get_value(e) == 2
-
- def test_textbox(self):
- e = FormElement.auto('_str')
- assert isinstance(e, TextBoxElement)
- assert get_value(e) == 'str'
-
- def test_recognizes_subsubclasses(self):
-
- class SubClassFormElement(TextBoxElement):
- @classmethod
- def recognizes(cls, params):
- return params == 'specific_class'
-
- e = FormElement.auto('specific_class')
- assert isinstance(e, SubClassFormElement)
-
- def test_unrecognized(self):
- with pytest.raises(ValueError):
- FormElement.auto(None)
diff --git a/glue/viewers/histogram/qt/__init__.py b/glue/viewers/histogram/qt/__init__.py
index e9447c8a0..96226f2e9 100644
--- a/glue/viewers/histogram/qt/__init__.py
+++ b/glue/viewers/histogram/qt/__init__.py
@@ -1,6 +1,4 @@
-from .data_viewer import HistogramViewer # noqa
-
-
-def setup():
- from glue.config import qt_client
- qt_client.add(HistogramViewer)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.histogram.qt is deprecated, use glue_qt.viewers.histogram instead', GlueDeprecationWarning)
+from glue_qt.viewers.histogram import * # noqa
diff --git a/glue/viewers/histogram/qt/data_viewer.py b/glue/viewers/histogram/qt/data_viewer.py
index f1ee0457c..c294f9bfb 100644
--- a/glue/viewers/histogram/qt/data_viewer.py
+++ b/glue/viewers/histogram/qt/data_viewer.py
@@ -1,31 +1,4 @@
-from glue.utils import defer_draw, decorate_all_methods
-from glue.viewers.matplotlib.qt.data_viewer import MatplotlibDataViewer
-from glue.viewers.histogram.qt.layer_style_editor import HistogramLayerStyleEditor
-from glue.viewers.histogram.qt.options_widget import HistogramOptionsWidget
-from glue.viewers.histogram.qt.layer_artist import QThreadedHistogramLayerArtist
-from glue.viewers.histogram.state import HistogramViewerState
-
-from glue.viewers.histogram.viewer import MatplotlibHistogramMixin
-
-__all__ = ['HistogramViewer']
-
-
-@decorate_all_methods(defer_draw)
-class HistogramViewer(MatplotlibHistogramMixin, MatplotlibDataViewer):
-
- LABEL = '1D Histogram'
-
- _layer_style_widget_cls = HistogramLayerStyleEditor
- _options_cls = HistogramOptionsWidget
-
- _state_cls = HistogramViewerState
- _data_artist_cls = QThreadedHistogramLayerArtist
- _subset_artist_cls = QThreadedHistogramLayerArtist
-
- large_data_size = 2e7
-
- tools = ['select:xrange']
-
- def __init__(self, session, parent=None, state=None):
- super(HistogramViewer, self).__init__(session, parent=parent, state=state)
- MatplotlibHistogramMixin.setup_callbacks(self)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.histogram.qt.data_viewer is deprecated, use glue_qt.viewers.histogram.data_viewer instead', GlueDeprecationWarning)
+from glue_qt.viewers.histogram.data_viewer import * # noqa
diff --git a/glue/viewers/histogram/qt/layer_artist.py b/glue/viewers/histogram/qt/layer_artist.py
index 5a1bfa13e..693af623e 100644
--- a/glue/viewers/histogram/qt/layer_artist.py
+++ b/glue/viewers/histogram/qt/layer_artist.py
@@ -1,61 +1,4 @@
-import time
-from glue.utils import defer_draw
-from glue.viewers.histogram.layer_artist import HistogramLayerArtist
-from glue.viewers.matplotlib.qt.compute_worker import ComputeWorker
-
-__all__ = ['QThreadedHistogramLayerArtist']
-
-
-class QThreadedHistogramLayerArtist(HistogramLayerArtist):
-
- def __init__(self, axes, viewer_state, layer_state=None, layer=None):
-
- super(QThreadedHistogramLayerArtist, self).__init__(axes, viewer_state,
- layer_state=layer_state, layer=layer)
-
- self.setup_thread()
-
- def wait(self):
- # Wait 0.5 seconds to make sure that the computation has properly started
- time.sleep(0.5)
- while self._worker.running:
- time.sleep(1 / 25)
- from glue.utils.qt import process_events
- process_events()
-
- def remove(self):
- super(QThreadedHistogramLayerArtist, self).remove()
- if self._worker is not None:
- self._worker.work_queue.put('stop')
- self._worker.exit()
- # Need to wait otherwise the thread will be destroyed while still
- # running, causing a segmentation fault
- self._worker.wait()
- self._worker = None
-
- @property
- def is_computing(self):
- return self._worker is not None and self._worker.running
-
- def setup_thread(self):
- self._worker = ComputeWorker(self._calculate_histogram_thread)
- self._worker.compute_end.connect(self._calculate_histogram_postthread)
- self._worker.compute_error.connect(self._calculate_histogram_error)
- self._worker.compute_start.connect(self.notify_start_computation)
- self._worker.start()
-
- @defer_draw
- def _calculate_histogram(self, reset=False):
- if self.state.layer is not None and self.state.layer.size > 1e7:
- self._worker.work_queue.put(reset)
- else:
- super(QThreadedHistogramLayerArtist, self)._calculate_histogram(reset=reset)
-
- def _calculate_histogram_postthread(self):
-
- # If the worker has started running again, we should stop at this point
- # since this function will get called again.
- if self._worker is not None and self._worker.running:
- return
-
- super(QThreadedHistogramLayerArtist, self)._calculate_histogram_postthread()
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.histogram.qt.layer_artist is deprecated, use glue_qt.viewers.histogram.layer_artist instead', GlueDeprecationWarning)
+from glue_qt.viewers.histogram.layer_artist import * # noqa
diff --git a/glue/viewers/histogram/qt/layer_style_editor.py b/glue/viewers/histogram/qt/layer_style_editor.py
index b4a7474d7..96f7f1f29 100644
--- a/glue/viewers/histogram/qt/layer_style_editor.py
+++ b/glue/viewers/histogram/qt/layer_style_editor.py
@@ -1,20 +1,4 @@
-import os
-
-from qtpy import QtWidgets
-
-from echo.qt import autoconnect_callbacks_to_qt
-from glue.utils.qt import load_ui
-
-
-class HistogramLayerStyleEditor(QtWidgets.QWidget):
-
- def __init__(self, layer, parent=None):
-
- super(HistogramLayerStyleEditor, self).__init__(parent=parent)
-
- self.ui = load_ui('layer_style_editor.ui', self,
- directory=os.path.dirname(__file__))
-
- connect_kwargs = {'alpha': dict(value_range=(0, 1))}
-
- self._connections = autoconnect_callbacks_to_qt(layer.state, self.ui, connect_kwargs)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.histogram.qt.layer_style_editor is deprecated, use glue_qt.viewers.histogram.layer_style_editor instead', GlueDeprecationWarning)
+from glue_qt.viewers.histogram.layer_style_editor import * # noqa
diff --git a/glue/viewers/histogram/qt/layer_style_editor.ui b/glue/viewers/histogram/qt/layer_style_editor.ui
deleted file mode 100644
index 3eb8b7b20..000000000
--- a/glue/viewers/histogram/qt/layer_style_editor.ui
+++ /dev/null
@@ -1,127 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 154
- 96
-
-
-
- Form
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 10
-
-
- 5
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- color
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- opacity
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- 100
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 5
-
-
-
-
-
-
-
-
- QColorBox
- QLabel
-
-
-
-
-
-
diff --git a/glue/viewers/histogram/qt/options_widget.py b/glue/viewers/histogram/qt/options_widget.py
index 4c2562105..3a7c880eb 100644
--- a/glue/viewers/histogram/qt/options_widget.py
+++ b/glue/viewers/histogram/qt/options_widget.py
@@ -1,48 +1,4 @@
-import os
-
-from qtpy import QtWidgets
-
-from echo.qt import autoconnect_callbacks_to_qt
-from glue.utils.qt import load_ui, fix_tab_widget_fontsize
-from glue.viewers.matplotlib.state import MatplotlibDataViewerState
-
-__all__ = ['HistogramOptionsWidget']
-
-
-class HistogramOptionsWidget(QtWidgets.QWidget):
-
- def __init__(self, viewer_state, session, parent=None):
-
- super(HistogramOptionsWidget, self).__init__(parent=parent)
-
- self.ui = load_ui('options_widget.ui', self,
- directory=os.path.dirname(__file__))
-
- fix_tab_widget_fontsize(self.ui.tab_widget)
-
- self._connections = autoconnect_callbacks_to_qt(viewer_state, self.ui)
- self._connections_axes = autoconnect_callbacks_to_qt(viewer_state, self.ui.axes_editor.ui)
- connect_kwargs = {'alpha': dict(value_range=(0, 1))}
- self._connections_legend = autoconnect_callbacks_to_qt(viewer_state.legend, self.ui.legend_editor.ui, connect_kwargs)
-
- self.viewer_state = viewer_state
-
- viewer_state.add_callback('x_att', self._update_attribute)
-
- self.session = session
- self.ui.axes_editor.button_apply_all.clicked.connect(self._apply_all_viewers)
-
- def _apply_all_viewers(self):
- for tab in self.session.application.viewers:
- for viewer in tab:
- if isinstance(viewer.state, MatplotlibDataViewerState):
- viewer.state.update_axes_settings_from(self.viewer_state)
-
- def _update_attribute(self, *args):
- # If at least one of the components is categorical or a date, disable log button
- log_enabled = 'categorical' not in self.viewer_state.x_kinds
- self.ui.bool_x_log.setEnabled(log_enabled)
- self.ui.bool_x_log_.setEnabled(log_enabled)
- if not log_enabled:
- self.ui.bool_x_log.setChecked(False)
- self.ui.bool_x_log_.setChecked(False)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.histogram.qt.options_widget is deprecated, use glue_qt.viewers.histogram.options_widget instead', GlueDeprecationWarning)
+from glue_qt.viewers.histogram.options_widget import * # noqa
diff --git a/glue/viewers/histogram/qt/options_widget.ui b/glue/viewers/histogram/qt/options_widget.ui
deleted file mode 100644
index eda9080db..000000000
--- a/glue/viewers/histogram/qt/options_widget.ui
+++ /dev/null
@@ -1,462 +0,0 @@
-
-
- Widget
-
-
-
- 0
- 0
- 269
- 418
-
-
-
- 1D Histogram
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
- 0
-
-
-
- General
-
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 5
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 5
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- normalized
-
-
- true
-
-
-
- -
-
-
- cumulative
-
-
- true
-
-
-
- -
-
-
- log
-
-
- true
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 1
- 20
-
-
-
-
-
-
-
- -
-
-
- -
-
-
-
- 50
- false
-
-
-
- bins
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Update bins to view
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 5
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Fixed
-
-
-
- 20
- 5
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- -
-
-
-
- 75
- true
-
-
-
- y axis
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Fixed # of numerical bins
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- x axis
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- true
-
-
- 1000
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
- log
-
-
- true
-
-
-
-
-
-
-
- Limits
-
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 5
-
- -
-
-
- padding: 0px
-
-
- ⇄
-
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
-
- 75
- true
-
-
-
- x axis
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- y axis
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 5
-
-
-
-
- -
-
-
- log
-
-
- true
-
-
-
- -
-
-
- log
-
-
- true
-
-
-
-
- bool_x_log
- valuetext_x_max
- button_flip_x
- valuetext_x_min
- valuetext_y_min
- valuetext_y_max
- bool_y_log
- label_2
- label_5
- verticalSpacer
- horizontalSpacer_2
-
-
-
- Axes
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
-
-
-
-
- Legend
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
-
-
-
-
-
-
-
-
-
- AxesEditorWidget
- QWidget
- glue.viewers.matplotlib.qt.axes_editor
-
-
- LegendEditorWidget
- QWidget
- glue.viewers.matplotlib.qt.legend_editor
-
-
-
-
-
diff --git a/glue/viewers/histogram/qt/tests/__init__.py b/glue/viewers/histogram/qt/tests/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/glue/viewers/histogram/qt/tests/data/histogram_v0.glu b/glue/viewers/histogram/qt/tests/data/histogram_v0.glu
deleted file mode 100644
index a481fefc2..000000000
--- a/glue/viewers/histogram/qt/tests/data/histogram_v0.glu
+++ /dev/null
@@ -1,397 +0,0 @@
-{
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDEwLCksIH0gICAgICAgICAgIAoAAAAAAAAAAAEAAAAAAAAAAgAAAAAAAAADAAAAAAAAAAQAAAAAAAAABQAAAAAAAAAGAAAAAAAAAAcAAAAAAAAACAAAAAAAAAAJAAAAAAAAAA=="
- },
- "units": ""
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDEwLCksIH0gICAgICAgICAgIAoAAAAAAAAAAAIAAAAAAAAABAAAAAAAAAAGAAAAAAAAAAgAAAAAAAAACgAAAAAAAAAMAAAAAAAAAA4AAAAAAAAAEAAAAAAAAAASAAAAAAAAAA=="
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0",
- "b"
- ],
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component_0"
- ],
- "data": [
- "data"
- ],
- "groups": [
- "Subset 1_0"
- ],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0"
- ],
- "subset_group_count": 1
- },
- "HistogramWidget": {
- "_type": "glue.viewers.histogram.qt.viewer_widget.HistogramWidget",
- "layers": [
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "hi": 9,
- "layer": "data",
- "lo": 0,
- "nbins": 6.0,
- "visible": true,
- "xlog": false,
- "zorder": 1
- },
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "hi": 9,
- "layer": "Subset 1",
- "lo": 0,
- "nbins": 6.0,
- "visible": false,
- "xlog": false,
- "zorder": 2
- }
- ],
- "pos": [
- 0,
- 0
- ],
- "properties": {
- "autoscale": true,
- "component": "a",
- "cumulative": false,
- "nbins": 6.0,
- "normed": false,
- "xlog": false,
- "xmax": 9.0,
- "xmin": 0.0,
- "ylog": false
- },
- "session": "Session",
- "size": [
- 600,
- 400
- ]
- },
- "HistogramWidget_0": {
- "_type": "glue.viewers.histogram.qt.viewer_widget.HistogramWidget",
- "layers": [
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "hi": 16.0,
- "layer": "data",
- "lo": 2.0,
- "nbins": 8.0,
- "visible": true,
- "xlog": false,
- "zorder": 1
- },
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "hi": 16.0,
- "layer": "Subset 1",
- "lo": 2.0,
- "nbins": 8.0,
- "visible": true,
- "xlog": false,
- "zorder": 2
- }
- ],
- "pos": [
- 502,
- 362
- ],
- "properties": {
- "autoscale": true,
- "component": "b",
- "cumulative": false,
- "nbins": 8.0,
- "normed": false,
- "xlog": false,
- "xmax": 16.0,
- "xmin": 2.0,
- "ylog": false
- },
- "session": "Session",
- "size": [
- 600,
- 400
- ]
- },
- "HistogramWidget_1": {
- "_type": "glue.viewers.histogram.qt.viewer_widget.HistogramWidget",
- "layers": [
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "hi": 9,
- "layer": "data",
- "lo": 0,
- "nbins": 10.0,
- "visible": true,
- "xlog": false,
- "zorder": 1
- },
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "hi": 9,
- "layer": "Subset 1",
- "lo": 0,
- "nbins": 10.0,
- "visible": true,
- "xlog": false,
- "zorder": 2
- }
- ],
- "pos": [
- 502,
- 0
- ],
- "properties": {
- "autoscale": true,
- "component": "a",
- "cumulative": false,
- "nbins": 10.0,
- "normed": true,
- "xlog": false,
- "xmax": 9.0,
- "xmin": 0.0,
- "ylog": true
- },
- "session": "Session",
- "size": [
- 600,
- 400
- ]
- },
- "HistogramWidget_2": {
- "_type": "glue.viewers.histogram.qt.viewer_widget.HistogramWidget",
- "layers": [
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "hi": 10.0,
- "layer": "data",
- "lo": -1.0,
- "nbins": 4.0,
- "visible": true,
- "xlog": false,
- "zorder": 1
- },
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "hi": 10.0,
- "layer": "Subset 1",
- "lo": -1.0,
- "nbins": 4.0,
- "visible": true,
- "xlog": false,
- "zorder": 2
- }
- ],
- "pos": [
- 0,
- 362
- ],
- "properties": {
- "autoscale": true,
- "component": "a",
- "cumulative": true,
- "nbins": 4.0,
- "normed": false,
- "xlog": false,
- "xmax": 10.0,
- "xmin": -1.0,
- "ylog": false
- },
- "session": "Session",
- "size": [
- 600,
- 400
- ]
- },
- "Pixel Axis 0 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [x]"
- },
- "RangeSubsetState": {
- "_type": "glue.core.subset.RangeSubsetState",
- "att": "a",
- "hi": 4.5,
- "lo": 1.5
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "Subset 1": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 1_0",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- }
- },
- "Subset 1_0": {
- "_type": "glue.core.subset_group.SubsetGroup",
- "label": "Subset 1",
- "state": "RangeSubsetState",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- },
- "subsets": [
- "Subset 1"
- ]
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue_vispy_viewers.scatter",
- "glue.plugins.tools.spectrum_tool",
- "glue.viewers.table",
- "glue.viewers.histogram",
- "glue.viewers.scatter",
- "glue.viewers.image",
- "glue.plugins.tools.pv_slicer",
- "glue.plugins.coordinate_helpers",
- "glue.plugins.exporters.plotly",
- "glue.plugins.export_d3po",
- "glue.core.data_exporters",
- "glue_h5part",
- "glue_vispy_viewers.volume"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- [
- "HistogramWidget",
- "HistogramWidget_0",
- "HistogramWidget_1",
- "HistogramWidget_2"
- ]
- ]
- },
- "a": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "a"
- },
- "b": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "b"
- },
- "data": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "a",
- "Component"
- ],
- [
- "Pixel Axis 0 [x]",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "b",
- "Component_0"
- ]
- ],
- "coords": "Coordinates",
- "label": "data",
- "primary_owner": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0",
- "b"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "0.35",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [
- "Subset 1"
- ],
- "uuid": "103f82ee-7731-4816-b207-164b683762d2"
- }
-}
\ No newline at end of file
diff --git a/glue/viewers/histogram/qt/tests/data/histogram_v1.glu b/glue/viewers/histogram/qt/tests/data/histogram_v1.glu
deleted file mode 100644
index 973a8ae58..000000000
--- a/glue/viewers/histogram/qt/tests/data/histogram_v1.glu
+++ /dev/null
@@ -1,516 +0,0 @@
-{
- "CallbackList": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "HistogramLayerState",
- "HistogramLayerState_0"
- ]
- },
- "CallbackList_0": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "HistogramLayerState_1",
- "HistogramLayerState_2"
- ]
- },
- "CallbackList_1": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "HistogramLayerState_3",
- "HistogramLayerState_4"
- ]
- },
- "CallbackList_2": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "HistogramLayerState_5",
- "HistogramLayerState_6"
- ]
- },
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDEwLCksIH0gICAgICAgICAgIAoAAAAAAAAAAAEAAAAAAAAAAgAAAAAAAAADAAAAAAAAAAQAAAAAAAAABQAAAAAAAAAGAAAAAAAAAAcAAAAAAAAACAAAAAAAAAAJAAAAAAAAAA=="
- },
- "units": ""
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDEwLCksIH0gICAgICAgICAgIAoAAAAAAAAAAAIAAAAAAAAABAAAAAAAAAAGAAAAAAAAAAgAAAAAAAAACgAAAAAAAAAMAAAAAAAAAA4AAAAAAAAAEAAAAAAAAAASAAAAAAAAAA=="
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]"
- ]
- },
- "CoordinateComponentLink_1": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]"
- ]
- },
- "CoordinateComponentLink_2": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0",
- "b"
- ],
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component_0"
- ],
- "data": [
- "data"
- ],
- "groups": [
- "Subset 1"
- ],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0",
- "CoordinateComponentLink_1",
- "CoordinateComponentLink_2"
- ],
- "subset_group_count": 1
- },
- "HistogramLayerState": {
- "_type": "glue.viewers.histogram.state.HistogramLayerState",
- "values": {
- "alpha": 0.8,
- "color": "st__0.35",
- "layer": "data",
- "visible": true,
- "zorder": 2
- }
- },
- "HistogramLayerState_0": {
- "_type": "glue.viewers.histogram.state.HistogramLayerState",
- "values": {
- "alpha": 0.5,
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "visible": false,
- "zorder": 3
- }
- },
- "HistogramLayerState_1": {
- "_type": "glue.viewers.histogram.state.HistogramLayerState",
- "values": {
- "alpha": 0.8,
- "color": "st__0.35",
- "layer": "data",
- "visible": true,
- "zorder": 2
- }
- },
- "HistogramLayerState_2": {
- "_type": "glue.viewers.histogram.state.HistogramLayerState",
- "values": {
- "alpha": 0.5,
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "visible": true,
- "zorder": 3
- }
- },
- "HistogramLayerState_3": {
- "_type": "glue.viewers.histogram.state.HistogramLayerState",
- "values": {
- "alpha": 0.8,
- "color": "st__0.35",
- "layer": "data",
- "visible": true,
- "zorder": 2
- }
- },
- "HistogramLayerState_4": {
- "_type": "glue.viewers.histogram.state.HistogramLayerState",
- "values": {
- "alpha": 0.5,
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "visible": true,
- "zorder": 3
- }
- },
- "HistogramLayerState_5": {
- "_type": "glue.viewers.histogram.state.HistogramLayerState",
- "values": {
- "alpha": 0.8,
- "color": "st__0.35",
- "layer": "data",
- "visible": true,
- "zorder": 2
- }
- },
- "HistogramLayerState_6": {
- "_type": "glue.viewers.histogram.state.HistogramLayerState",
- "values": {
- "alpha": 0.5,
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "visible": true,
- "zorder": 3
- }
- },
- "HistogramViewer": {
- "_protocol": 1,
- "_type": "glue.viewers.histogram.qt.data_viewer.HistogramViewer",
- "layers": [
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "state": "HistogramLayerState"
- },
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "state": "HistogramLayerState_0"
- }
- ],
- "pos": [
- 664,
- 475
- ],
- "session": "Session",
- "size": [
- 663,
- 473
- ],
- "state": {
- "values": {
- "common_n_bin": true,
- "cumulative": false,
- "hist_n_bin": 6,
- "hist_x_max": 9.0,
- "hist_x_min": 0.0,
- "layers": "CallbackList",
- "normalize": false,
- "x_att": "a",
- "x_log": false,
- "x_max": 9.0,
- "x_min": 0.0,
- "y_log": false,
- "y_max": 2.4,
- "y_min": 0
- }
- }
- },
- "HistogramViewer_0": {
- "_protocol": 1,
- "_type": "glue.viewers.histogram.qt.data_viewer.HistogramViewer",
- "layers": [
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "state": "HistogramLayerState_1"
- },
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "state": "HistogramLayerState_2"
- }
- ],
- "pos": [
- 0,
- 475
- ],
- "session": "Session",
- "size": [
- 664,
- 473
- ],
- "state": {
- "values": {
- "common_n_bin": true,
- "cumulative": false,
- "hist_n_bin": 8,
- "hist_x_max": 16.0,
- "hist_x_min": 2.0,
- "layers": "CallbackList_0",
- "normalize": false,
- "x_att": "b",
- "x_log": false,
- "x_max": 16.0,
- "x_min": 2.0,
- "y_log": false,
- "y_max": 1.2,
- "y_min": 0
- }
- }
- },
- "HistogramViewer_1": {
- "_protocol": 1,
- "_type": "glue.viewers.histogram.qt.data_viewer.HistogramViewer",
- "layers": [
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "state": "HistogramLayerState_3"
- },
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "state": "HistogramLayerState_4"
- }
- ],
- "pos": [
- 664,
- 0
- ],
- "session": "Session",
- "size": [
- 663,
- 475
- ],
- "state": {
- "values": {
- "common_n_bin": true,
- "cumulative": false,
- "hist_n_bin": 10,
- "hist_x_max": 9.0,
- "hist_x_min": 0.0,
- "layers": "CallbackList_1",
- "normalize": true,
- "x_att": "a",
- "x_log": false,
- "x_max": 9.0,
- "x_min": 0.0,
- "y_log": true,
- "y_max": 0.7407407407407407,
- "y_min": 0.01111111111111111
- }
- }
- },
- "HistogramViewer_2": {
- "_protocol": 1,
- "_type": "glue.viewers.histogram.qt.data_viewer.HistogramViewer",
- "layers": [
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "state": "HistogramLayerState_5"
- },
- {
- "_type": "glue.viewers.histogram.layer_artist.HistogramLayerArtist",
- "state": "HistogramLayerState_6"
- }
- ],
- "pos": [
- 0,
- 0
- ],
- "session": "Session",
- "size": [
- 664,
- 475
- ],
- "state": {
- "values": {
- "common_n_bin": true,
- "cumulative": true,
- "hist_n_bin": 4,
- "hist_x_max": 10.0,
- "hist_x_min": -1.0,
- "layers": "CallbackList_2",
- "normalize": false,
- "x_att": "a",
- "x_log": false,
- "x_max": 10.0,
- "x_min": -1.0,
- "y_log": false,
- "y_max": 12.0,
- "y_min": 0
- }
- }
- },
- "Pixel Axis 0 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [x]"
- },
- "RangeSubsetState": {
- "_type": "glue.core.subset.RangeSubsetState",
- "att": "a",
- "hi": 4.5,
- "lo": 1.5
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "Subset 1": {
- "_type": "glue.core.subset_group.SubsetGroup",
- "label": "Subset 1",
- "state": "RangeSubsetState",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- },
- "subsets": [
- "Subset 1_0"
- ]
- },
- "Subset 1_0": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 1",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- }
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue_vispy_viewers.scatter",
- "glue.plugins.coordinate_helpers",
- "glue.plugins.exporters.plotly",
- "glue.viewers.table",
- "glue.core.data_exporters",
- "glue_medical",
- "glue.plugins.tools.pv_slicer",
- "specviz.app",
- "glue.viewers.scatter",
- "glue.viewers.histogram",
- "glue_vispy_viewers.volume",
- "glue.plugins.tools.spectrum_tool",
- "glue.plugins.export_d3po",
- "glue.viewers.image"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- [
- "HistogramViewer",
- "HistogramViewer_0",
- "HistogramViewer_1",
- "HistogramViewer_2"
- ]
- ]
- },
- "a": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "a"
- },
- "b": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "b"
- },
- "data": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "a",
- "Component"
- ],
- [
- "Pixel Axis 0 [x]",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "b",
- "Component_0"
- ]
- ],
- "coords": "Coordinates",
- "label": "data",
- "primary_owner": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0",
- "b"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "0.35",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [
- "Subset 1_0"
- ],
- "uuid": "103f82ee-7731-4816-b207-164b683762d2"
- }
-}
diff --git a/glue/viewers/histogram/qt/tests/test_data_viewer.py b/glue/viewers/histogram/qt/tests/test_data_viewer.py
deleted file mode 100644
index 14482dc1f..000000000
--- a/glue/viewers/histogram/qt/tests/test_data_viewer.py
+++ /dev/null
@@ -1,743 +0,0 @@
-# pylint: disable=I0011,W0613,W0201,W0212,E1101,E1103
-
-import os
-from collections import Counter
-
-import pytest
-import numpy as np
-
-from numpy.testing import assert_equal, assert_allclose
-
-from glue.core.message import SubsetUpdateMessage
-from glue.core import HubListener, Data
-from glue.core.roi import XRangeROI, RectangularROI
-from glue.core.subset import SubsetState, RangeSubsetState, CategoricalROISubsetState, RoiSubsetState
-from glue import core
-from glue.app.qt import GlueApplication
-from glue.core.component_id import ComponentID
-from glue.utils.qt import combo_as_string, process_events
-from glue.viewers.matplotlib.qt.tests.test_data_viewer import BaseTestMatplotlibDataViewer
-from glue.core.state import GlueUnSerializer
-from glue.app.qt.layer_tree_widget import LayerTreeWidget
-from glue.tests.helpers import requires_matplotlib_ge_22
-
-from ..data_viewer import HistogramViewer
-
-DATA = os.path.join(os.path.dirname(__file__), 'data')
-
-
-class TestHistogramCommon(BaseTestMatplotlibDataViewer):
- def init_data(self):
- return Data(label='d1', x=[3.4, 2.3, -1.1, 0.3], y=['a', 'b', 'c', 'a'])
- viewer_cls = HistogramViewer
-
-
-class TestHistogramViewer(object):
-
- def setup_method(self, method):
-
- self.data = Data(label='d1', x=[3.4, 2.3, -1.1, 0.3], y=['a', 'b', 'c', 'a'])
-
- self.app = GlueApplication()
- self.session = self.app.session
- self.hub = self.session.hub
-
- self.data_collection = self.session.data_collection
- self.data_collection.append(self.data)
-
- self.viewer = self.app.new_data_viewer(HistogramViewer)
-
- def teardown_method(self, method):
- self.viewer.close()
- self.viewer = None
- self.app.close()
- self.app = None
-
- def test_basic(self):
-
- viewer_state = self.viewer.state
-
- # Check defaults when we add data
- self.viewer.add_data(self.data)
-
- assert combo_as_string(self.viewer.options_widget().ui.combosel_x_att) == 'Main components:x:y:Coordinate components:Pixel Axis 0 [x]'
-
- assert viewer_state.x_att is self.data.id['x']
- assert viewer_state.x_min == -1.1
- assert viewer_state.x_max == 3.4
- assert viewer_state.y_min == 0.0
- assert viewer_state.y_max == 1.2
-
- assert viewer_state.hist_x_min == -1.1
- assert viewer_state.hist_x_max == 3.4
- assert viewer_state.hist_n_bin == 15
-
- assert not viewer_state.cumulative
- assert not viewer_state.normalize
-
- assert not viewer_state.x_log
- assert not viewer_state.y_log
-
- assert len(viewer_state.layers) == 1
-
- # Change to categorical component and check new values
-
- viewer_state.x_att = self.data.id['y']
-
- assert viewer_state.x_min == -0.5
- assert viewer_state.x_max == 2.5
- assert viewer_state.y_min == 0.0
- assert viewer_state.y_max == 2.4
-
- assert viewer_state.hist_x_min == -0.5
- assert viewer_state.hist_x_max == 2.5
- assert viewer_state.hist_n_bin == 3
-
- assert not viewer_state.cumulative
- assert not viewer_state.normalize
-
- assert not viewer_state.x_log
- assert not viewer_state.y_log
-
- def test_log_labels(self):
-
- # Regression test to make sure the labels are correctly changed to log
- # when the x-axis is in log space.
-
- viewer_state = self.viewer.state
- data = Data(x=np.logspace(-5, 5, 10000))
- self.data_collection.append(data)
-
- self.viewer.add_data(data)
- viewer_state.x_log = True
-
- process_events()
-
- labels = [x.get_text() for x in self.viewer.axes.xaxis.get_ticklabels()]
-
- # Different Matplotlib versions return slightly different
- # labels, but the ones below should be present regardless
- # of Matplotlib version.
- expected_present = ['$\\mathdefault{10^{-5}}$',
- '$\\mathdefault{10^{-3}}$',
- '$\\mathdefault{10^{-1}}$',
- '$\\mathdefault{10^{1}}$',
- '$\\mathdefault{10^{3}}$',
- '$\\mathdefault{10^{5}}$']
-
- for label in expected_present:
- assert label in labels
-
- def test_flip(self):
-
- viewer_state = self.viewer.state
-
- self.viewer.add_data(self.data)
-
- assert viewer_state.x_min == -1.1
- assert viewer_state.x_max == 3.4
-
- self.viewer.options_widget().button_flip_x.click()
-
- assert viewer_state.x_min == 3.4
- assert viewer_state.x_max == -1.1
-
- def test_remove_data(self):
- self.viewer.add_data(self.data)
- assert combo_as_string(self.viewer.options_widget().ui.combosel_x_att) == 'Main components:x:y:Coordinate components:Pixel Axis 0 [x]'
- self.data_collection.remove(self.data)
- assert combo_as_string(self.viewer.options_widget().ui.combosel_x_att) == ''
-
- def test_update_component_updates_title(self):
- self.viewer.add_data(self.data)
- assert self.viewer.windowTitle() == '1D Histogram'
- self.viewer.state.x_att = self.data.id['y']
- assert self.viewer.windowTitle() == '1D Histogram'
-
- def test_combo_updates_with_component_add(self):
- self.viewer.add_data(self.data)
- self.data.add_component([3, 4, 1, 2], 'z')
- assert self.viewer.state.x_att is self.data.id['x']
- assert combo_as_string(self.viewer.options_widget().ui.combosel_x_att) == 'Main components:x:y:z:Coordinate components:Pixel Axis 0 [x]'
-
- def test_nonnumeric_first_component(self):
- # regression test for #208. Shouldn't complain if
- # first component is non-numerical
- data = core.Data()
- data.add_component(['a', 'b', 'c'], label='c1')
- data.add_component([1, 2, 3], label='c2')
- self.data_collection.append(data)
- self.viewer.add_data(data)
-
- def test_nan_component(self):
- # regression test for case when all values are NaN in a component
- data = core.Data()
- data.add_component([np.nan, np.nan, np.nan], label='c1')
- self.data_collection.append(data)
- self.viewer.add_data(data)
-
- def test_histogram_values(self):
-
- # Check the actual values of the histograms
-
- viewer_state = self.viewer.state
-
- self.viewer.add_data(self.data)
-
- # Numerical attribute
-
- viewer_state.hist_x_min = -5
- viewer_state.hist_x_max = 5
- viewer_state.hist_n_bin = 4
-
- assert_allclose(self.viewer.state.y_max, 2.4)
-
- assert_allclose(self.viewer.layers[0].state.histogram[1], [0, 1, 2, 1])
- assert_allclose(self.viewer.layers[0].state.histogram[0], [-5, -2.5, 0, 2.5, 5])
-
- cid = self.data.main_components[0]
- self.data_collection.new_subset_group('subset 1', cid < 2)
-
- assert_allclose(self.viewer.layers[1].state.histogram[1], [0, 1, 1, 0])
- assert_allclose(self.viewer.layers[1].state.histogram[0], [-5, -2.5, 0, 2.5, 5])
-
- viewer_state.normalize = True
-
- assert_allclose(self.viewer.state.y_max, 0.24)
- assert_allclose(self.viewer.layers[0].state.histogram[1], [0, 0.1, 0.2, 0.1])
- assert_allclose(self.viewer.layers[0].state.histogram[0], [-5, -2.5, 0, 2.5, 5])
- assert_allclose(self.viewer.layers[1].state.histogram[1], [0, 0.2, 0.2, 0])
- assert_allclose(self.viewer.layers[1].state.histogram[0], [-5, -2.5, 0, 2.5, 5])
-
- viewer_state.cumulative = True
-
- assert_allclose(self.viewer.state.y_max, 1.2)
- assert_allclose(self.viewer.layers[0].state.histogram[1], [0, 0.25, 0.75, 1.0])
- assert_allclose(self.viewer.layers[0].state.histogram[0], [-5, -2.5, 0, 2.5, 5])
- assert_allclose(self.viewer.layers[1].state.histogram[1], [0, 0.5, 1.0, 1.0])
- assert_allclose(self.viewer.layers[1].state.histogram[0], [-5, -2.5, 0, 2.5, 5])
-
- viewer_state.normalize = False
-
- assert_allclose(self.viewer.state.y_max, 4.8)
- assert_allclose(self.viewer.layers[0].state.histogram[1], [0, 1, 3, 4])
- assert_allclose(self.viewer.layers[0].state.histogram[0], [-5, -2.5, 0, 2.5, 5])
- assert_allclose(self.viewer.layers[1].state.histogram[1], [0, 1, 2, 2])
- assert_allclose(self.viewer.layers[1].state.histogram[0], [-5, -2.5, 0, 2.5, 5])
-
- viewer_state.cumulative = False
-
- # Categorical attribute
-
- viewer_state.x_att = self.data.id['y']
-
- formatter = self.viewer.axes.xaxis.get_major_formatter()
- xlabels = [formatter.format_data(pos) for pos in range(3)]
- assert xlabels == ['a', 'b', 'c']
-
- assert_allclose(self.viewer.state.y_max, 2.4)
- assert_allclose(self.viewer.layers[0].state.histogram[1], [2, 1, 1])
- assert_allclose(self.viewer.layers[0].state.histogram[0], [-0.5, 0.5, 1.5, 2.5])
- assert_allclose(self.viewer.layers[1].state.histogram[1], [1, 0, 1])
- assert_allclose(self.viewer.layers[1].state.histogram[0], [-0.5, 0.5, 1.5, 2.5])
-
- viewer_state.normalize = True
-
- assert_allclose(self.viewer.state.y_max, 0.6)
- assert_allclose(self.viewer.layers[0].state.histogram[1], [0.5, 0.25, 0.25])
- assert_allclose(self.viewer.layers[0].state.histogram[0], [-0.5, 0.5, 1.5, 2.5])
- assert_allclose(self.viewer.layers[1].state.histogram[1], [0.5, 0, 0.5])
- assert_allclose(self.viewer.layers[1].state.histogram[0], [-0.5, 0.5, 1.5, 2.5])
-
- viewer_state.cumulative = True
-
- assert_allclose(self.viewer.state.y_max, 1.2)
- assert_allclose(self.viewer.layers[0].state.histogram[1], [0.5, 0.75, 1])
- assert_allclose(self.viewer.layers[0].state.histogram[0], [-0.5, 0.5, 1.5, 2.5])
- assert_allclose(self.viewer.layers[1].state.histogram[1], [0.5, 0.5, 1])
- assert_allclose(self.viewer.layers[1].state.histogram[0], [-0.5, 0.5, 1.5, 2.5])
-
- viewer_state.normalize = False
-
- assert_allclose(self.viewer.state.y_max, 4.8)
- assert_allclose(self.viewer.layers[0].state.histogram[1], [2, 3, 4])
- assert_allclose(self.viewer.layers[0].state.histogram[0], [-0.5, 0.5, 1.5, 2.5])
- assert_allclose(self.viewer.layers[1].state.histogram[1], [1, 1, 2])
- assert_allclose(self.viewer.layers[1].state.histogram[0], [-0.5, 0.5, 1.5, 2.5])
-
- # TODO: add tests for log
-
- def test_apply_roi(self):
-
- # Check that when doing an ROI selection, the ROI clips to the bin edges
- # outside the selection
-
- viewer_state = self.viewer.state
-
- self.viewer.add_data(self.data)
-
- viewer_state.hist_x_min = -5
- viewer_state.hist_x_max = 5
- viewer_state.hist_n_bin = 4
-
- roi = XRangeROI(-0.2, 0.1)
-
- assert len(self.viewer.layers) == 1
-
- self.viewer.apply_roi(roi)
-
- assert len(self.viewer.layers) == 2
-
- assert_allclose(self.viewer.layers[0].state.histogram[1], [0, 1, 2, 1])
- assert_allclose(self.viewer.layers[1].state.histogram[1], [0, 1, 2, 0])
-
- assert_allclose(self.data.subsets[0].to_mask(), [0, 1, 1, 1])
-
- state = self.data.subsets[0].subset_state
- assert isinstance(state, RangeSubsetState)
-
- assert state.lo == -2.5
- assert state.hi == 2.5
-
- # TODO: add a similar test in log space
-
- def test_apply_roi_categorical(self):
-
- # Check that when doing an ROI selection, the ROI clips to the bin edges
- # outside the selection
-
- viewer_state = self.viewer.state
-
- self.viewer.add_data(self.data)
-
- viewer_state.x_att = self.data.id['y']
-
- roi = XRangeROI(0.3, 0.9)
-
- assert len(self.viewer.layers) == 1
-
- self.viewer.apply_roi(roi)
-
- assert len(self.viewer.layers) == 2
-
- assert_allclose(self.viewer.layers[0].state.histogram[1], [2, 1, 1])
- assert_allclose(self.viewer.layers[1].state.histogram[1], [2, 1, 0])
-
- assert_allclose(self.data.subsets[0].to_mask(), [1, 1, 0, 1])
-
- state = self.data.subsets[0].subset_state
- assert isinstance(state, CategoricalROISubsetState)
-
- assert_equal(state.roi.categories, ['a', 'b'])
-
- def test_apply_roi_empty(self):
- # Make sure that doing an ROI selection on an empty viewer doesn't
- # produce error messsages
- roi = XRangeROI(-0.2, 0.1)
- self.viewer.apply_roi(roi)
-
- def test_axes_labels(self):
-
- viewer_state = self.viewer.state
-
- self.viewer.add_data(self.data)
-
- assert self.viewer.axes.get_xlabel() == 'x'
- assert self.viewer.axes.get_ylabel() == 'Number'
-
- viewer_state.x_log = True
-
- assert self.viewer.axes.get_xlabel() == 'x'
- assert self.viewer.axes.get_ylabel() == 'Number'
-
- viewer_state.x_att = self.data.id['y']
-
- assert self.viewer.axes.get_xlabel() == 'y'
- assert self.viewer.axes.get_ylabel() == 'Number'
-
- viewer_state.normalize = True
-
- assert self.viewer.axes.get_xlabel() == 'y'
- assert self.viewer.axes.get_ylabel() == 'Normalized number'
-
- viewer_state.normalize = False
- viewer_state.cumulative = True
-
- assert self.viewer.axes.get_xlabel() == 'y'
- assert self.viewer.axes.get_ylabel() == 'Number'
-
- def test_y_min_y_max(self):
-
- # Regression test for a bug that caused y_max to not be set correctly
- # when multiple subsets were present and after turning on normalization
- # after switching to a different attribute from that used to make the
- # selection.
-
- viewer_state = self.viewer.state
- self.viewer.add_data(self.data)
-
- self.data.add_component([3.4, 3.5, 10.2, 20.3], 'z')
-
- viewer_state.x_att = self.data.id['x']
-
- cid = self.data.main_components[0]
- self.data_collection.new_subset_group('subset 1', cid < 1)
-
- cid = self.data.main_components[0]
- self.data_collection.new_subset_group('subset 2', cid < 2)
-
- cid = self.data.main_components[0]
- self.data_collection.new_subset_group('subset 3', cid < 3)
-
- assert_allclose(self.viewer.state.y_min, 0)
- assert_allclose(self.viewer.state.y_max, 1.2)
-
- viewer_state.x_att = self.data.id['z']
-
- assert_allclose(self.viewer.state.y_min, 0)
- assert_allclose(self.viewer.state.y_max, 2.4)
-
- viewer_state.normalize = True
-
- assert_allclose(self.viewer.state.y_min, 0)
- assert_allclose(self.viewer.state.y_max, 0.5325443786982249)
-
- def test_update_when_limits_unchanged(self):
-
- # Regression test for glue-viz/glue#1010 - this bug caused histograms
- # to not be recomputed if the attribute changed but the limits and
- # number of bins did not.
-
- viewer_state = self.viewer.state
-
- self.viewer.add_data(self.data)
-
- viewer_state.x_att = self.data.id['y']
- viewer_state.hist_x_min = -10.1
- viewer_state.hist_x_max = +10
- viewer_state.hist_n_bin = 5
-
- assert_allclose(self.viewer.layers[0].state.histogram[1], [0, 0, 3, 1, 0])
-
- viewer_state.x_att = self.data.id['x']
- viewer_state.hist_x_min = -10.1
- viewer_state.hist_x_max = +10
- viewer_state.hist_n_bin = 5
-
- assert_allclose(self.viewer.layers[0].state.histogram[1], [0, 0, 2, 2, 0])
-
- viewer_state.x_att = self.data.id['y']
-
- assert_allclose(self.viewer.layers[0].state.histogram[1], [0, 0, 3, 1, 0])
-
- viewer_state.x_att = self.data.id['x']
-
- assert_allclose(self.viewer.layers[0].state.histogram[1], [0, 0, 2, 2, 0])
-
- def test_component_replaced(self):
-
- # regression test for 508 - if a component ID is replaced, we should
- # make sure that the component ID is selected if the old component ID
- # was selected
-
- self.viewer.add_data(self.data)
- self.viewer.state.x_att = self.data.id['x']
- test = ComponentID('test')
- self.data.update_id(self.viewer.state.x_att, test)
- assert self.viewer.state.x_att is test
- assert combo_as_string(self.viewer.options_widget().ui.combosel_x_att) == 'Main components:test:y:Coordinate components:Pixel Axis 0 [x]'
-
- def test_nbin_override_persists_over_numerical_attribute_change(self):
-
- # regression test for #398
-
- self.data.add_component([3, 4, 1, 2], 'z')
-
- self.viewer.add_data(self.data)
- self.viewer.state.x_att = self.data.id['x']
- self.viewer.state.hist_n_bin = 7
- self.viewer.state.x_att = self.data.id['z']
- assert self.viewer.state.hist_n_bin == 7
-
- @pytest.mark.parametrize('protocol', [0, 1])
- def test_session_back_compat(self, protocol):
-
- filename = os.path.join(DATA, 'histogram_v{0}.glu'.format(protocol))
-
- with open(filename, 'r') as f:
- session = f.read()
-
- state = GlueUnSerializer.loads(session)
-
- ga = state.object('__main__')
-
- dc = ga.session.data_collection
-
- assert len(dc) == 1
-
- assert dc[0].label == 'data'
-
- viewer1 = ga.viewers[0][0]
- assert len(viewer1.state.layers) == 2
- assert viewer1.state.x_att is dc[0].id['a']
- assert_allclose(viewer1.state.x_min, 0)
- assert_allclose(viewer1.state.x_max, 9)
- assert_allclose(viewer1.state.y_min, 0)
- assert_allclose(viewer1.state.y_max, 2.4)
- assert_allclose(viewer1.state.hist_x_min, 0)
- assert_allclose(viewer1.state.hist_x_max, 9)
- assert_allclose(viewer1.state.hist_n_bin, 6)
- assert not viewer1.state.x_log
- assert not viewer1.state.y_log
- assert viewer1.state.layers[0].visible
- assert not viewer1.state.layers[1].visible
- assert not viewer1.state.cumulative
- assert not viewer1.state.normalize
-
- viewer2 = ga.viewers[0][1]
- assert viewer2.state.x_att is dc[0].id['b']
- assert_allclose(viewer2.state.x_min, 2)
- assert_allclose(viewer2.state.x_max, 16)
- assert_allclose(viewer2.state.y_min, 0)
- assert_allclose(viewer2.state.y_max, 1.2)
- assert_allclose(viewer2.state.hist_x_min, 2)
- assert_allclose(viewer2.state.hist_x_max, 16)
- assert_allclose(viewer2.state.hist_n_bin, 8)
- assert not viewer2.state.x_log
- assert not viewer2.state.y_log
- assert viewer2.state.layers[0].visible
- assert viewer2.state.layers[1].visible
- assert not viewer2.state.cumulative
- assert not viewer2.state.normalize
-
- viewer3 = ga.viewers[0][2]
- assert viewer3.state.x_att is dc[0].id['a']
- assert_allclose(viewer3.state.x_min, 0)
- assert_allclose(viewer3.state.x_max, 9)
- assert_allclose(viewer3.state.y_min, 0.01111111111111111)
- assert_allclose(viewer3.state.y_max, 0.7407407407407407)
- assert_allclose(viewer3.state.hist_x_min, 0)
- assert_allclose(viewer3.state.hist_x_max, 9)
- assert_allclose(viewer3.state.hist_n_bin, 10)
- assert not viewer3.state.x_log
- assert viewer3.state.y_log
- assert viewer3.state.layers[0].visible
- assert viewer3.state.layers[1].visible
- assert not viewer3.state.cumulative
- assert viewer3.state.normalize
-
- viewer4 = ga.viewers[0][3]
- assert viewer4.state.x_att is dc[0].id['a']
- assert_allclose(viewer4.state.x_min, -1)
- assert_allclose(viewer4.state.x_max, 10)
- assert_allclose(viewer4.state.y_min, 0)
- assert_allclose(viewer4.state.y_max, 12)
- assert_allclose(viewer4.state.hist_x_min, -1)
- assert_allclose(viewer4.state.hist_x_max, 10)
- assert_allclose(viewer4.state.hist_n_bin, 4)
- assert not viewer4.state.x_log
- assert not viewer4.state.y_log
- assert viewer4.state.layers[0].visible
- assert viewer4.state.layers[1].visible
- assert viewer4.state.cumulative
- assert not viewer4.state.normalize
-
- ga.close()
-
- def test_apply_roi_single(self):
-
- # Regression test for a bug that caused mode.update to be called
- # multiple times and resulted in all other viewers receiving many
- # messages regarding subset updates (this occurred when multiple)
- # datasets were present.
-
- layer_tree = LayerTreeWidget(session=self.session)
- layer_tree.set_checkable(False)
- layer_tree.setup(self.data_collection)
- layer_tree.bind_selection_to_edit_subset()
-
- class Client(HubListener):
-
- def __init__(self, *args, **kwargs):
- super(Client, self).__init__(*args, **kwargs)
- self.count = Counter()
-
- def ping(self, message):
- self.count[message.sender] += 1
-
- def register_to_hub(self, hub):
- hub.subscribe(self, SubsetUpdateMessage, handler=self.ping)
-
- d1 = Data(a=[1, 2, 3], label='d1')
- d2 = Data(b=[1, 2, 3], label='d2')
- d3 = Data(c=[1, 2, 3], label='d3')
- d4 = Data(d=[1, 2, 3], label='d4')
-
- self.data_collection.append(d1)
- self.data_collection.append(d2)
- self.data_collection.append(d3)
- self.data_collection.append(d4)
-
- client = Client()
- client.register_to_hub(self.hub)
-
- self.viewer.add_data(d1)
- self.viewer.add_data(d3)
-
- roi = XRangeROI(2.5, 3.5)
- self.viewer.apply_roi(roi)
-
- for subset in client.count:
- assert client.count[subset] == 1
-
- @pytest.mark.filterwarnings('ignore:elementwise')
- def test_datetime64_support(self, tmpdir):
-
- self.data.add_component(np.array([100, 200, 300, 400], dtype='M8[D]'), 't1')
- self.viewer.add_data(self.data)
- self.viewer.state.x_att = self.data.id['t1']
-
- # Matplotlib deals with dates by converting them to the number of days
- # since 01-01-0001, so we can check that the limits are correctly
- # converted (and not 100 to 400)
- assert self.viewer.axes.get_xlim() == (719263.0, 719563.0)
-
- # Apply an ROI selection in plotting coordinates
- roi = XRangeROI(719313, 719513)
- self.viewer.apply_roi(roi)
-
- # Check that the two middle elements are selected
- assert_equal(self.data.subsets[0].to_mask(), [0, 1, 1, 0])
-
- # Make sure that the Qt labels look ok
- options = self.viewer.options_widget().ui
- assert options.valuetext_x_min.text() == '1970-04-11'
- assert options.valuetext_x_max.text() == '1971-02-05'
-
- # Make sure that we can set the xmin/xmax to a string date
- assert_equal(self.viewer.state.x_min, np.datetime64('1970-04-11', 'D'))
- options.valuetext_x_min.setText('1970-04-14')
- options.valuetext_x_min.editingFinished.emit()
- assert self.viewer.axes.get_xlim() == (719266.0, 719563.0)
- assert_equal(self.viewer.state.x_min, np.datetime64('1970-04-14', 'D'))
-
- # Make sure that everything works fine after saving/reloading
- filename = tmpdir.join('test_datetime64.glu').strpath
- self.session.application.save_session(filename)
- with open(filename, 'r') as f:
- session = f.read()
- state = GlueUnSerializer.loads(session)
- ga = state.object('__main__')
- viewer = ga.viewers[0][0]
- options = viewer.options_widget().ui
-
- assert_equal(self.viewer.state.x_min, np.datetime64('1970-04-14', 'D'))
-
- assert options.valuetext_x_min.text() == '1970-04-14'
- assert options.valuetext_x_max.text() == '1971-02-05'
-
- ga.close()
-
- @requires_matplotlib_ge_22
- def test_categorical_labels(self, tmpdir):
-
- # Fix a bug that caused labels on histograms of categorical variables
- # to not be restored correctly after saving and reloading session
-
- self.viewer.add_data(self.data)
- self.viewer.state.x_att = self.data.id['y']
-
- self.viewer.figure.canvas.draw()
-
- assert [x.get_text() for x in self.viewer.axes.xaxis.get_ticklabels()] == ['', 'a', 'b', 'c', '']
-
- # Make sure that everything works fine after saving/reloading
- filename = tmpdir.join('test_categorical_labels.glu').strpath
- self.session.application.save_session(filename)
- with open(filename, 'r') as f:
- session = f.read()
- state = GlueUnSerializer.loads(session)
- ga = state.object('__main__')
- viewer = ga.viewers[0][0]
-
- viewer.figure.canvas.draw()
-
- assert [x.get_text() for x in viewer.axes.xaxis.get_ticklabels()] == ['', 'a', 'b', 'c', '']
-
- ga.close()
-
- def test_legend(self):
- from matplotlib.colors import to_hex
-
- viewer_state = self.viewer.state
-
- self.viewer.add_data(self.data)
- self.viewer.state.legend.visible = True
-
- handles, labels, handler_dict = self.viewer.get_handles_legend()
- assert len(handles) == 1
- assert labels[0] == 'd1'
-
- self.data_collection.new_subset_group('test', self.data.id['x'] > 1)
- assert len(viewer_state.layers) == 2
- handles, labels, handler_dict = self.viewer.get_handles_legend()
- assert len(handles) == 2
- assert labels[1] == 'test'
-
- assert to_hex(handles[1].get_facecolor()) == viewer_state.layers[1].color
-
- def test_redraw_empty_subset(self):
- self.viewer.add_data(self.data)
- self.data_collection.new_subset_group('redraw_empty', self.data.id['x'] > 1)
- layer_artist = self.viewer.layers[-1]
- subset = layer_artist.layer
- subset.subset_state = SubsetState()
- for artist in layer_artist.mpl_artists:
- assert artist.get_height() == 0
-
-
-def test_with_dask_array():
-
- # Regression test for a bug that caused the histogram to now work when
- # making spatial selections on a cube represented as a dask array
-
- da = pytest.importorskip('dask.array')
-
- data = Data(x=da.arange(1000).reshape((10, 10, 10)), label='d1')
-
- app = GlueApplication()
- session = app.session
- hub = session.hub
-
- data_collection = session.data_collection
- data_collection.append(data)
-
- viewer = app.new_data_viewer(HistogramViewer)
-
- viewer.add_data(data)
-
- viewer.state.hist_n_bin = 1
-
- process_events(0.5)
-
- assert len(viewer.layers) == 1
- assert viewer.layers[0].enabled
-
- zid, yid, xid = data.pixel_component_ids
-
- subset_state = RoiSubsetState(xatt=xid, yatt=yid,
- roi=RectangularROI(xmin=3.5, xmax=5.5, ymin=3.7, ymax=7.5))
-
- data_collection.new_subset_group(subset_state=subset_state, label='subset')
-
- assert len(viewer.layers) == 2
- assert viewer.layers[0].enabled
- assert viewer.layers[1].enabled
-
- assert viewer.state.layers[0].histogram[1][0] == 1000.
- assert viewer.state.layers[1].histogram[1][0] == 80.
-
- viewer.close()
- viewer = None
- app.close()
- app = None
diff --git a/glue/viewers/histogram/qt/tests/test_python_export.py b/glue/viewers/histogram/qt/tests/test_python_export.py
deleted file mode 100644
index 987fd0050..000000000
--- a/glue/viewers/histogram/qt/tests/test_python_export.py
+++ /dev/null
@@ -1,63 +0,0 @@
-from astropy.utils import NumpyRNGContext
-
-from glue.core import Data, DataCollection
-from glue.app.qt.application import GlueApplication
-from glue.viewers.histogram.qt import HistogramViewer
-from glue.viewers.matplotlib.qt.tests.test_python_export import BaseTestExportPython, random_with_nan
-
-
-class TestExportPython(BaseTestExportPython):
-
- def setup_method(self, method):
-
- with NumpyRNGContext(12345):
- self.data = Data(**dict((name, random_with_nan(100, nan_index=idx + 1)) for idx, name in enumerate('abcdefgh')))
- self.data_collection = DataCollection([self.data])
- self.app = GlueApplication(self.data_collection)
- self.viewer = self.app.new_data_viewer(HistogramViewer)
- self.viewer.add_data(self.data)
- self.viewer.state.x_att = self.data.id['a']
-
- def teardown_method(self, method):
- self.viewer.close()
- self.viewer = None
- self.app.close()
- self.app = None
-
- def test_simple(self, tmpdir):
- self.assert_same(tmpdir)
-
- def test_simple_visual(self, tmpdir):
- self.viewer.state.layers[0].color = 'blue'
- self.viewer.state.layers[0].alpha = 0.5
- self.assert_same(tmpdir)
-
- def test_simple_visual_legend(self, tmpdir):
- self.viewer.state.legend.visible = True
- self.viewer.state.layers[0].color = 'blue'
- self.viewer.state.layers[0].alpha = 0.5
- self.assert_same(tmpdir)
-
- def test_cumulative(self, tmpdir):
- self.viewer.state.cumulative = True
- self.assert_same(tmpdir)
-
- def test_normalize(self, tmpdir):
- self.viewer.state.normalize = True
- self.assert_same(tmpdir)
-
- def test_subset(self, tmpdir):
- self.data_collection.new_subset_group('mysubset', self.data.id['a'] > 0.5)
- self.assert_same(tmpdir)
-
- def test_subset_legend(self, tmpdir):
- self.viewer.state.legend.visible = True
- self.data_collection.new_subset_group('mysubset', self.data.id['a'] > 0.5)
- self.assert_same(tmpdir)
-
- def test_empty(self, tmpdir):
- self.viewer.state.x_min = 10
- self.viewer.state.x_max = 11
- self.viewer.state.hist_x_min = 10
- self.viewer.state.hist_x_max = 11
- self.assert_same(tmpdir)
diff --git a/glue/viewers/image/composite_array.py b/glue/viewers/image/composite_array.py
index 1742c60fa..323bc3348 100644
--- a/glue/viewers/image/composite_array.py
+++ b/glue/viewers/image/composite_array.py
@@ -5,11 +5,10 @@
import numpy as np
-from glue.config import colormaps
+from glue.config import colormaps, stretches
from matplotlib.colors import ColorConverter, Colormap
-from astropy.visualization import (LinearStretch, SqrtStretch, AsinhStretch,
- LogStretch, ManualInterval, ContrastBiasStretch)
+from astropy.visualization import ManualInterval, ContrastBiasStretch
__all__ = ['CompositeArray']
@@ -18,13 +17,6 @@
CMAP_SAMPLING = np.linspace(0, 1, 256)
-STRETCHES = {
- 'linear': LinearStretch,
- 'sqrt': SqrtStretch,
- 'arcsinh': AsinhStretch,
- 'log': LogStretch
-}
-
class CompositeArray(object):
@@ -126,7 +118,7 @@ def __call__(self, bounds=None):
interval = ManualInterval(*layer['clim'])
contrast_bias = ContrastBiasStretch(layer['contrast'], layer['bias'])
- stretch = STRETCHES[layer['stretch']]()
+ stretch = stretches.members[layer['stretch']]
if callable(layer['array']):
array = layer['array'](bounds=bounds)
@@ -145,21 +137,29 @@ def __call__(self, bounds=None):
data = interval(array)
data = contrast_bias(data, out=data)
data = stretch(data, out=data)
- data[np.isnan(data)] = 0
if self.mode == 'colormap':
+ # ensure "bad" values have the same alpha as the
+ # rest of the layer:
+ if hasattr(layer['cmap'], 'get_bad'):
+ bad_color = layer['cmap'].get_bad().tolist()[:3]
+ layer_cmap = layer['cmap'].with_extremes(
+ bad=bad_color + [layer['alpha']]
+ )
+ else:
+ layer_cmap = layer['cmap']
+
if img is None:
img = np.ones(data.shape + (4,))
# Compute colormapped image
- plane = layer['cmap'](data)
+ plane = layer_cmap(data)
# Check what the smallest colormap alpha value for this layer is
# - if it is 1 then this colormap does not change transparency,
# and this allows us to speed things up a little.
-
- if layer['cmap'](CMAP_SAMPLING)[:, 3].min() == 1:
+ if layer_cmap(CMAP_SAMPLING)[:, 3].min() == 1:
if layer['alpha'] == 1:
img[...] = 0
@@ -170,7 +170,6 @@ def __call__(self, bounds=None):
else:
# Use traditional alpha compositing
-
alpha_plane = layer['alpha'] * plane[:, :, 3]
plane[:, :, 0] = plane[:, :, 0] * alpha_plane
@@ -184,7 +183,6 @@ def __call__(self, bounds=None):
img[:, :, 3] = 1
else:
-
if img is None:
img = np.zeros(data.shape + (4,))
diff --git a/glue/viewers/image/qt/__init__.py b/glue/viewers/image/qt/__init__.py
index 63a0b2170..5444f7485 100644
--- a/glue/viewers/image/qt/__init__.py
+++ b/glue/viewers/image/qt/__init__.py
@@ -1,7 +1,4 @@
-from .data_viewer import ImageViewer # noqa
-from .standalone_image_viewer import StandaloneImageViewer # noqa
-
-
-def setup():
- from glue.config import qt_client
- qt_client.add(ImageViewer)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.image.qt is deprecated, use glue_qt.viewers.image instead', GlueDeprecationWarning)
+from glue_qt.viewers.image import * # noqa
diff --git a/glue/viewers/image/qt/contrast_mouse_mode.py b/glue/viewers/image/qt/contrast_mouse_mode.py
index 52fa167ce..37d452705 100644
--- a/glue/viewers/image/qt/contrast_mouse_mode.py
+++ b/glue/viewers/image/qt/contrast_mouse_mode.py
@@ -1,38 +1,4 @@
-# New contrast/bias mode that operates on viewers with state objects
-
-from echo import delay_callback
-from glue.config import viewer_tool
-from glue.viewers.matplotlib.toolbar_mode import ToolbarModeBase
-
-
-@viewer_tool
-class ContrastBiasMode(ToolbarModeBase):
- """
- Uses right mouse button drags to set bias and contrast, DS9-style. The
- horizontal position of the mouse sets the bias, the vertical position sets
- the contrast.
- """
-
- icon = 'glue_contrast'
- tool_id = 'image:contrast_bias'
- action_text = 'Contrast/Bias'
- tool_tip = 'Adjust the bias/contrast'
- status_tip = ('CLICK and DRAG on image from left to right to adjust '
- 'bias and up and down to adjust contrast')
-
- def move(self, event):
- """
- Update bias and contrast on Right Mouse button drag.
- """
-
- if event.button not in (1, 3):
- return
-
- x, y = self.viewer.axes.transAxes.inverted().transform((event.x, event.y))
- state = self.viewer.selected_layer.state
-
- with delay_callback(state, 'bias', 'contrast'):
- state.bias = -(x * 2 - 1.5)
- state.contrast = 10. ** (y * 2 - 1)
-
- super(ContrastBiasMode, self).move(event)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.image.qt.contrast_mouse_mode is deprecated, use glue_qt.viewers.image.contrast_mouse_mode instead', GlueDeprecationWarning)
+from glue_qt.viewers.image.contrast_mouse_mode import * # noqa
diff --git a/glue/viewers/image/qt/data_viewer.py b/glue/viewers/image/qt/data_viewer.py
index c78a443f0..7499d72a3 100644
--- a/glue/viewers/image/qt/data_viewer.py
+++ b/glue/viewers/image/qt/data_viewer.py
@@ -1,52 +1,4 @@
-from glue.viewers.matplotlib.qt.data_viewer import MatplotlibDataViewer
-from glue.viewers.scatter.qt.layer_style_editor import ScatterLayerStyleEditor
-from glue.viewers.scatter.layer_artist import ScatterLayerArtist
-from glue.viewers.image.qt.layer_style_editor import ImageLayerStyleEditor
-from glue.viewers.image.qt.layer_style_editor_subset import ImageLayerSubsetStyleEditor
-from glue.viewers.image.layer_artist import ImageLayerArtist, ImageSubsetLayerArtist
-from glue.viewers.image.qt.options_widget import ImageOptionsWidget
-from glue.viewers.image.qt.mouse_mode import RoiClickAndDragMode
-from glue.viewers.image.state import ImageViewerState
-from glue.utils import defer_draw, decorate_all_methods
-
-# Import the mouse mode to make sure it gets registered
-from glue.viewers.image.qt.contrast_mouse_mode import ContrastBiasMode # noqa
-from glue.viewers.image.qt.profile_viewer_tool import ProfileViewerTool # noqa
-from glue.viewers.image.qt.pixel_selection_mode import PixelSelectionTool # noqa
-
-from glue.viewers.image.viewer import MatplotlibImageMixin
-
-__all__ = ['ImageViewer']
-
-
-@decorate_all_methods(defer_draw)
-class ImageViewer(MatplotlibImageMixin, MatplotlibDataViewer):
-
- LABEL = '2D Image'
- _default_mouse_mode_cls = RoiClickAndDragMode
- _layer_style_widget_cls = {ImageLayerArtist: ImageLayerStyleEditor,
- ImageSubsetLayerArtist: ImageLayerSubsetStyleEditor,
- ScatterLayerArtist: ScatterLayerStyleEditor}
- _state_cls = ImageViewerState
- _options_cls = ImageOptionsWidget
-
- allow_duplicate_data = True
-
- # NOTE: _data_artist_cls and _subset_artist_cls are not defined - instead
- # we override get_data_layer_artist and get_subset_layer_artist for
- # more advanced logic.
-
- tools = ['select:rectangle', 'select:xrange',
- 'select:yrange', 'select:circle',
- 'select:polygon', 'image:point_selection', 'image:contrast_bias',
- 'profile-viewer']
-
- def __init__(self, session, parent=None, state=None):
- MatplotlibDataViewer.__init__(self, session, wcs=True, parent=parent, state=state)
- MatplotlibImageMixin.setup_callbacks(self)
-
- def closeEvent(self, *args):
- super(ImageViewer, self).closeEvent(*args)
- if self.axes._composite_image is not None:
- self.axes._composite_image.remove()
- self.axes._composite_image = None
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.image.qt.data_viewer is deprecated, use glue_qt.viewers.image.data_viewer instead', GlueDeprecationWarning)
+from glue_qt.viewers.image.data_viewer import * # noqa
diff --git a/glue/viewers/image/qt/layer_style_editor.py b/glue/viewers/image/qt/layer_style_editor.py
index c76b10326..253591c36 100644
--- a/glue/viewers/image/qt/layer_style_editor.py
+++ b/glue/viewers/image/qt/layer_style_editor.py
@@ -1,36 +1,4 @@
-import os
-
-from qtpy import QtWidgets
-
-from echo.qt import autoconnect_callbacks_to_qt
-from glue.utils.qt import load_ui
-
-
-class ImageLayerStyleEditor(QtWidgets.QWidget):
-
- def __init__(self, layer, parent=None):
-
- super(ImageLayerStyleEditor, self).__init__(parent=parent)
-
- self.ui = load_ui('layer_style_editor.ui', self,
- directory=os.path.dirname(__file__))
-
- connect_kwargs = {'alpha': dict(value_range=(0, 1)),
- 'contrast': dict(value_range=(0.1, 10), log=True),
- 'bias': dict(value_range=(1.5, -0.5))}
-
- self._connections = autoconnect_callbacks_to_qt(layer.state, self.ui, connect_kwargs)
-
- layer._viewer_state.add_callback('color_mode', self._update_color_mode)
-
- self._update_color_mode(layer._viewer_state.color_mode)
-
- self.ui.bool_global_sync.setToolTip('Whether to sync the color and transparency with other viewers')
-
- def _update_color_mode(self, color_mode):
- if color_mode == 'Colormaps':
- self.ui.color_color.hide()
- self.ui.combodata_cmap.show()
- else:
- self.ui.color_color.show()
- self.ui.combodata_cmap.hide()
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.image.qt.layer_style_editor is deprecated, use glue_qt.viewers.image.layer_style_editor instead', GlueDeprecationWarning)
+from glue_qt.viewers.image.layer_style_editor import * # noqa
diff --git a/glue/viewers/image/qt/layer_style_editor.ui b/glue/viewers/image/qt/layer_style_editor.ui
deleted file mode 100644
index a655323b1..000000000
--- a/glue/viewers/image/qt/layer_style_editor.ui
+++ /dev/null
@@ -1,309 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 292
- 197
-
-
-
- Form
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 10
-
-
- 5
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- attribute
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- limits
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- 10
-
-
-
-
-
-
-
-
-
- 80
- 0
-
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
- false
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 50
- 0
-
-
-
- 100
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- Sync
-
-
- true
-
-
-
-
-
- -
-
-
- 2
-
-
-
-
-
- -
-
-
- padding: 0px
-
-
- ⇄
-
-
-
- -
-
-
-
-
- -
-
-
-
- 50
- 0
-
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
-
- 50
- 0
-
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
- 10
-
-
-
-
-
-
- 50
- 0
-
-
-
- 1000
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 50
- 0
-
-
-
- 1000
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- Reset
-
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- contrast/bias
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- color/opacity
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 5
-
-
-
-
-
-
-
-
- QColorBox
- QLabel
-
-
-
- QColormapCombo
- QComboBox
-
-
-
-
-
-
diff --git a/glue/viewers/image/qt/layer_style_editor_subset.py b/glue/viewers/image/qt/layer_style_editor_subset.py
index 6173074fb..8713eb546 100644
--- a/glue/viewers/image/qt/layer_style_editor_subset.py
+++ b/glue/viewers/image/qt/layer_style_editor_subset.py
@@ -1,20 +1,4 @@
-import os
-
-from qtpy import QtWidgets
-
-from echo.qt import autoconnect_callbacks_to_qt
-from glue.utils.qt import load_ui
-
-
-class ImageLayerSubsetStyleEditor(QtWidgets.QWidget):
-
- def __init__(self, layer, parent=None):
-
- super(ImageLayerSubsetStyleEditor, self).__init__(parent=parent)
-
- self.ui = load_ui('layer_style_editor_subset.ui', self,
- directory=os.path.dirname(__file__))
-
- connect_kwargs = {'alpha': dict(value_range=(0, 1))}
-
- self._connections = autoconnect_callbacks_to_qt(layer.state, self.ui, connect_kwargs)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.image.qt.layer_style_editor_subset is deprecated, use glue_qt.viewers.image.layer_style_editor_subset instead', GlueDeprecationWarning)
+from glue_qt.viewers.image.layer_style_editor_subset import * # noqa
diff --git a/glue/viewers/image/qt/layer_style_editor_subset.ui b/glue/viewers/image/qt/layer_style_editor_subset.ui
deleted file mode 100644
index 3d3356f89..000000000
--- a/glue/viewers/image/qt/layer_style_editor_subset.ui
+++ /dev/null
@@ -1,102 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 234
- 55
-
-
-
- Form
-
-
-
- 5
-
-
- 5
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
- -
-
-
- 100
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- transparency
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- color
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
- QColorBox
- QLabel
-
-
-
-
-
-
diff --git a/glue/viewers/image/qt/mouse_mode.py b/glue/viewers/image/qt/mouse_mode.py
index effa4b468..bf4789933 100644
--- a/glue/viewers/image/qt/mouse_mode.py
+++ b/glue/viewers/image/qt/mouse_mode.py
@@ -1,96 +1,4 @@
-from qtpy.QtGui import QCursor
-from qtpy.QtWidgets import QMenu, QAction
-
-from glue.core.subset import RoiSubsetState
-from glue.core.roi import MplPolygonalROI
-from glue.core.edit_subset_mode import ReplaceMode
-from glue.viewers.matplotlib.mouse_mode import MouseMode
-from glue.viewers.image.layer_artist import ImageSubsetLayerArtist
-
-
-__all__ = ['RoiClickAndDragMode']
-
-
-_MPL_LEFT_CLICK = 1
-_MPL_RIGHT_CLICK = 3
-
-
-class RoiClickAndDragMode(MouseMode):
- """
- A MouseMode that enables clicking and dragging of existing ROIs.
- """
-
- def __init__(self, viewer, **kwargs):
- super(RoiClickAndDragMode, self).__init__(viewer, **kwargs)
-
- self._viewer = viewer
- self._dc = viewer.state.data_collection
- self._edit_subset_mode = viewer.session.edit_subset_mode
-
- self._roi = None
- self._subset = None
- self._selected = False
-
- def _select_roi(self, roi, index, event):
- self._roi = MplPolygonalROI(self._axes, roi=roi)
- self._roi.start_selection(event, scrubbing=True)
- self._edit_subset_mode.edit_subset = [self._dc.subset_groups[index]]
-
- def _deselect_roi(self, event):
-
- self._edit_subset_mode.edit_subset = []
-
- if self._roi:
- self._roi = None
- self._subset = None
-
- def _display_roi_context_menu(self, roi_index):
-
- def delete_roi(event):
- self._dc.remove_subset_group(self._dc.subset_groups[roi_index])
-
- context_menu = QMenu()
- action = QAction("Delete ROI", context_menu)
- action.triggered.connect(delete_roi)
- context_menu.addAction(action)
- pos = self._viewer.mapToParent(QCursor().pos())
- context_menu.exec_(pos)
-
- def press(self, event):
- # Ignore button presses outside the data viewer canvas
- if event.xdata is None or event.ydata is None:
- return
-
- x, y = (int(event.xdata + 0.5), int(event.ydata + 0.5))
-
- roi_index = 0
- for layer in self._viewer.layers:
- if not isinstance(layer, ImageSubsetLayerArtist):
- continue
-
- subset_state = layer.state.layer.subset_state
- if layer.visible and isinstance(subset_state, RoiSubsetState):
- if subset_state.roi.contains(x, y):
- if event.button == _MPL_LEFT_CLICK:
- self._select_roi(subset_state.roi, roi_index, event)
- self._subset = layer.state.layer
- elif event.button == _MPL_RIGHT_CLICK:
- self._display_roi_context_menu(roi_index)
- self._selected = True
- break
- roi_index += 1
- else:
- self._selected = False
- self._deselect_roi(event)
-
- def move(self, event):
- if self._roi is None or not self._selected:
- return
-
- self._roi.update_selection(event)
-
- def release(self, event):
- if self._roi:
- self._viewer.apply_roi(self._roi.roi(), override_mode=ReplaceMode)
- self._roi.finalize_selection(event)
- self._selected = False
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.image.qt.mouse_mode is deprecated, use glue_qt.viewers.image.mouse_mode instead', GlueDeprecationWarning)
+from glue_qt.viewers.image.mouse_mode import * # noqa
diff --git a/glue/viewers/image/qt/options_widget.py b/glue/viewers/image/qt/options_widget.py
index 3a005f3bc..b157c97de 100644
--- a/glue/viewers/image/qt/options_widget.py
+++ b/glue/viewers/image/qt/options_widget.py
@@ -1,41 +1,4 @@
-import os
-
-from qtpy import QtWidgets
-
-from echo.qt import autoconnect_callbacks_to_qt
-from glue.utils.qt import load_ui, fix_tab_widget_fontsize
-from glue.viewers.image.qt.slice_widget import MultiSliceWidgetHelper
-from glue.viewers.matplotlib.state import MatplotlibDataViewerState
-
-__all__ = ['ImageOptionsWidget']
-
-
-class ImageOptionsWidget(QtWidgets.QWidget):
-
- def __init__(self, viewer_state, session, parent=None):
-
- super(ImageOptionsWidget, self).__init__(parent=parent)
-
- self.ui = load_ui('options_widget.ui', self,
- directory=os.path.dirname(__file__))
-
- fix_tab_widget_fontsize(self.ui.tab_widget)
-
- self._connections = autoconnect_callbacks_to_qt(viewer_state, self.ui)
- self._connections_axes = autoconnect_callbacks_to_qt(viewer_state, self.ui.axes_editor.ui)
- connect_kwargs = {'alpha': dict(value_range=(0, 1))}
- self._connections_legend = autoconnect_callbacks_to_qt(viewer_state.legend, self.ui.legend_editor.ui, connect_kwargs)
-
- self.viewer_state = viewer_state
-
- self.slice_helper = MultiSliceWidgetHelper(viewer_state=self.viewer_state,
- layout=self.ui.layout_slices)
-
- self.session = session
- self.ui.axes_editor.button_apply_all.clicked.connect(self._apply_all_viewers)
-
- def _apply_all_viewers(self):
- for tab in self.session.application.viewers:
- for viewer in tab:
- if isinstance(viewer.state, MatplotlibDataViewerState):
- viewer.state.update_axes_settings_from(self.viewer_state)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.image.qt.options_widget is deprecated, use glue_qt.viewers.image.options_widget instead', GlueDeprecationWarning)
+from glue_qt.viewers.image.options_widget import * # noqa
diff --git a/glue/viewers/image/qt/options_widget.ui b/glue/viewers/image/qt/options_widget.ui
deleted file mode 100644
index dec488359..000000000
--- a/glue/viewers/image/qt/options_widget.ui
+++ /dev/null
@@ -1,401 +0,0 @@
-
-
- Widget
-
-
-
- 0
- 0
- 288
- 238
-
-
-
- 2D Image
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
- 0
-
-
-
- General
-
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 5
-
-
-
-
-
-
- 75
- true
-
-
-
- mode
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 5
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- reference
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- aspect
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- x axis
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- y axis
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
- Limits
-
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 5
-
- -
-
-
- padding: 0px
-
-
- ⇄
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- y axis
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 5
-
-
-
-
- -
-
-
- -
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- -
-
-
- -
-
-
-
- 75
- true
-
-
-
- x axis
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- padding: 0px
-
-
- ⇄
-
-
-
-
- label_2
- valuetext_x_min
- button_flip_x
- valuetext_x_max
- label_2
- valuetext_y_min
- button_flip_y
- valuetext_y_max
- verticalSpacer_3
- horizontalSpacer
-
-
-
- Axes
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
-
-
-
-
- Legend
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
-
-
-
-
-
-
-
-
-
- AxesEditorWidget
- QWidget
- glue.viewers.matplotlib.qt.axes_editor
-
-
- LegendEditorWidget
- QWidget
- glue.viewers.matplotlib.qt.legend_editor
-
-
-
-
-
diff --git a/glue/viewers/image/qt/pixel_selection_mode.py b/glue/viewers/image/qt/pixel_selection_mode.py
index 004d6ecbc..4bad22fc4 100644
--- a/glue/viewers/image/qt/pixel_selection_mode.py
+++ b/glue/viewers/image/qt/pixel_selection_mode.py
@@ -1,65 +1,4 @@
-from glue.config import viewer_tool
-
-from glue.core.command import ApplySubsetState
-from glue.core.edit_subset_mode import ReplaceMode
-
-from glue.viewers.matplotlib.toolbar_mode import ToolbarModeBase
-from glue.viewers.image.pixel_selection_subset_state import PixelSubsetState
-
-__all__ = ['PixelSelectionTool']
-
-
-@viewer_tool
-class PixelSelectionTool(ToolbarModeBase):
- """
- Selects pixel under mouse cursor.
- """
-
- icon = "glue_crosshair"
- tool_id = 'image:point_selection'
- action_text = 'Pixel'
- tool_tip = 'Select a single pixel based on mouse location'
- status_tip = 'CLICK to select a point, CLICK and DRAG to update the selection in real time'
-
- _pressed = False
-
- def __init__(self, *args, **kwargs):
- super(PixelSelectionTool, self).__init__(*args, **kwargs)
- self._move_callback = self._select_pixel
- self._press_callback = self._on_press
- self._release_callback = self._on_release
-
- def _on_press(self, mode):
- self._pressed = True
- self.viewer.session.edit_subset_mode.mode = ReplaceMode
- self._select_pixel(mode)
-
- def _on_release(self, mode):
- self._pressed = False
-
- def _select_pixel(self, mode):
- """
- Select a pixel
- """
-
- if not self._pressed:
- return
-
- x, y = self._event_xdata, self._event_ydata
-
- if x is None or y is None:
- return None
-
- x = int(round(x))
- y = int(round(y))
-
- slices = [slice(None)] * self.viewer.state.reference_data.ndim
- slices[self.viewer.state.x_att.axis] = slice(x, x + 1)
- slices[self.viewer.state.y_att.axis] = slice(y, y + 1)
-
- subset_state = PixelSubsetState(self.viewer.state.reference_data, slices)
-
- cmd = ApplySubsetState(data_collection=self.viewer._data,
- subset_state=subset_state,
- override_mode=None)
- self.viewer._session.command_stack.do(cmd)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.image.qt.pixel_selection_mode is deprecated, use glue_qt.viewers.image.pixel_selection_mode instead', GlueDeprecationWarning)
+from glue_qt.viewers.image.pixel_selection_mode import * # noqa
diff --git a/glue/viewers/image/qt/profile_viewer_tool.py b/glue/viewers/image/qt/profile_viewer_tool.py
index 48b110aab..c89021d39 100644
--- a/glue/viewers/image/qt/profile_viewer_tool.py
+++ b/glue/viewers/image/qt/profile_viewer_tool.py
@@ -1,80 +1,4 @@
-from glue.config import viewer_tool
-from glue.viewers.common.tool import Tool
-from glue.core.qt.dialogs import info, warn
-from glue.core.component_id import PixelComponentID
-
-
-@viewer_tool
-class ProfileViewerTool(Tool):
-
- icon = 'glue_spectrum'
- tool_id = 'profile-viewer'
-
- @property
- def profile_viewers_exist(self):
- from glue.viewers.profile.qt import ProfileViewer
- for tab in self.viewer.session.application.viewers:
- for viewer in tab:
- if isinstance(viewer, ProfileViewer):
- return True
- return False
-
- def activate(self):
-
- if self.profile_viewers_exist:
-
- proceed = warn('A profile viewer was already created',
- 'Do you really want to create a new one?',
- default='Cancel', setting='show_warn_profile_duplicate')
-
- if not proceed:
- return
-
- else:
-
- proceed = info('Creating a profile viewer',
- 'Note: profiles are '
- 'computed from datasets and subsets collapsed along all but one '
- 'dimension. To view the profile of part of the data, once you '
- 'click OK you can draw and update a subset in the current '
- 'image viewer and the profile will update accordingly.', setting='show_info_profile_open')
-
- if not proceed:
- return
-
- from glue.viewers.profile.qt import ProfileViewer
- profile_viewer = self.viewer.session.application.new_data_viewer(ProfileViewer)
- any_added = False
- for data in self.viewer.session.data_collection:
- if data in self.viewer._layer_artist_container:
- result = profile_viewer.add_data(data)
- any_added = any_added or result
-
- if not any_added:
- profile_viewer.close()
- return
-
- # If the reference data for the current image viewer is in the profile
- # viewer, we make sure that it is used as the reference data there too
- if self.viewer.state.reference_data in profile_viewer._layer_artist_container:
-
- profile_viewer.state.reference_data = self.viewer.state.reference_data
-
- # We now pick an attribute in the profile viewer that is one of the ones
- # with a slider in the image viewer. Note that the attribute viewer may
- # be a pixel attribute or world attribute depending on what information
- # is available in the coordinates, so we need to be careful about that.
-
- x_att = profile_viewer.state.x_att
- reference_data = self.viewer.state.reference_data
-
- if isinstance(profile_viewer.state.x_att, PixelComponentID):
- for att in reference_data.pixel_component_ids:
- if att is not self.viewer.state.x_att and att is not self.viewer.state.y_att:
- if att is not profile_viewer.state.x_att:
- profile_viewer.state.x_att = att
- else:
- for att in reference_data.world_component_ids:
- if att is not self.viewer.state.x_att_world and att is not self.viewer.state.y_att_world:
- if att is not profile_viewer.state.x_att:
- profile_viewer.state.x_att = att
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.image.qt.profile_viewer_tool is deprecated, use glue_qt.viewers.image.profile_viewer_tool instead', GlueDeprecationWarning)
+from glue_qt.viewers.image.profile_viewer_tool import * # noqa
diff --git a/glue/viewers/image/qt/slice_widget.py b/glue/viewers/image/qt/slice_widget.py
index 3fc80910b..692f4ea6c 100644
--- a/glue/viewers/image/qt/slice_widget.py
+++ b/glue/viewers/image/qt/slice_widget.py
@@ -1,149 +1,4 @@
-import numpy as np
-
-from glue.core.coordinates import LegacyCoordinates
-from glue.core.coordinate_helpers import dependent_axes, world_axis
-from glue.viewers.common.qt.data_slice_widget import SliceWidget
-from glue.viewers.image.state import AggregateSlice
-from glue.utils.decorators import avoid_circular
-
-__all__ = ['MultiSliceWidgetHelper']
-
-
-class MultiSliceWidgetHelper(object):
-
- def __init__(self, viewer_state=None, layout=None):
-
- self.viewer_state = viewer_state
-
- self.layout = layout
- self.layout.setSpacing(4)
- self.layout.setContentsMargins(0, 3, 0, 3)
-
- self.viewer_state.add_callback('x_att', self.sync_sliders_from_state)
- self.viewer_state.add_callback('y_att', self.sync_sliders_from_state)
- self.viewer_state.add_callback('slices', self.sync_sliders_from_state)
- self.viewer_state.add_callback('reference_data', self.sync_sliders_from_state)
-
- self._sliders = []
-
- self._reference_data = None
- self._x_att = None
- self._y_att = None
-
- self.sync_sliders_from_state()
-
- @property
- def data(self):
- return self.viewer_state.reference_data
-
- def _clear(self):
-
- for _ in range(self.layout.count()):
- self.layout.takeAt(0)
-
- for s in self._sliders:
- if s is not None:
- s.close()
-
- self._sliders = []
-
- @avoid_circular
- def sync_state_from_sliders(self, *args):
- slices = []
- for i, slider in enumerate(self._sliders):
- if slider is not None:
- slices.append(slider.state.slice_center)
- else:
- slices.append(self.viewer_state.slices[i])
- self.viewer_state.slices = tuple(slices)
-
- @avoid_circular
- def sync_sliders_from_state(self, *args):
-
- if self.data is None or self.viewer_state.x_att is None or self.viewer_state.y_att is None:
- return
-
- if self.viewer_state.x_att is self.viewer_state.y_att:
- return
-
- # Update sliders if needed
-
- if (self.viewer_state.reference_data is not self._reference_data or
- self.viewer_state.x_att is not self._x_att or
- self.viewer_state.y_att is not self._y_att):
-
- self._reference_data = self.viewer_state.reference_data
- self._x_att = self.viewer_state.x_att
- self._y_att = self.viewer_state.y_att
-
- self._clear()
-
- for i in range(self.data.ndim):
-
- if i == self.viewer_state.x_att.axis or i == self.viewer_state.y_att.axis:
- self._sliders.append(None)
- continue
-
- # TODO: For now we simply pass a single set of world coordinates,
- # but we will need to generalize this in future. We deliberately
- # check the type of data.coords here since we want to treat
- # subclasses differently.
- if getattr(self.data, 'coords') is not None and type(self.data.coords) != LegacyCoordinates:
- world_axis_index = self.data.ndim - 1 - i
- world = world_axis(self.data.coords, self.data,
- pixel_axis=world_axis_index,
- world_axis=world_axis_index)
- world_unit = self.data.coords.world_axis_units[world_axis_index]
- world_warning = len(dependent_axes(self.data.coords, i)) > 1
- world_label = self.data.world_component_ids[i].label
- else:
- world = None
- world_unit = None
- world_warning = False
- world_label = self.data.pixel_component_ids[i].label
-
- slider = SliceWidget(world_label,
- hi=self.data.shape[i] - 1, world=world,
- world_unit=world_unit, world_warning=world_warning)
-
- self.slider_state = slider.state
- self.slider_state.add_callback('slice_center', self.sync_state_from_sliders)
- self._sliders.append(slider)
- self.layout.addWidget(slider)
-
- for i in range(self.data.ndim):
- if self._sliders[i] is not None:
- if isinstance(self.viewer_state.slices[i], AggregateSlice):
- self._sliders[i].state.slice_center = self.viewer_state.slices[i].center
- else:
- self._sliders[i].state.slice_center = self.viewer_state.slices[i]
-
-
-if __name__ == "__main__":
-
- from glue.core import Data
- from glue.utils.qt import get_qapp
- from echo import CallbackProperty
- from glue.core.state_objects import State
-
- app = get_qapp()
-
- class FakeViewerState(State):
- x_att = CallbackProperty()
- y_att = CallbackProperty()
- reference_data = CallbackProperty()
- slices = CallbackProperty()
-
- viewer_state = FakeViewerState()
-
- data = Data(x=np.random.random((3, 50, 20, 5, 3)))
-
- viewer_state.reference_data = data
- viewer_state.x_att = data.pixel_component_ids[0]
- viewer_state.y_att = data.pixel_component_ids[3]
- viewer_state.slices = [0] * 5
-
- widget = MultiSliceWidgetHelper(viewer_state)
- widget.show()
-
- app.exec_()
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.image.qt.slice_widget is deprecated, use glue_qt.viewers.image.slice_widget instead', GlueDeprecationWarning)
+from glue_qt.viewers.image.slice_widget import * # noqa
diff --git a/glue/viewers/image/qt/standalone_image_viewer.py b/glue/viewers/image/qt/standalone_image_viewer.py
index 740ad1446..437466bba 100644
--- a/glue/viewers/image/qt/standalone_image_viewer.py
+++ b/glue/viewers/image/qt/standalone_image_viewer.py
@@ -1,168 +1,4 @@
-import numpy as np
-
-from qtpy import QtCore, QtWidgets
-
-from glue.config import colormaps
-from glue.viewers.common.qt.toolbar import BasicToolbar
-from glue.viewers.matplotlib.qt.widget import MplWidget
-from glue.viewers.image.composite_array import CompositeArray
-from glue.external.modest_image import imshow
-from glue.utils import defer_draw
-
-from glue.viewers.matplotlib.mpl_axes import init_mpl
-
-# Import the mouse mode to make sure it gets registered
-from glue.viewers.image.qt.contrast_mouse_mode import ContrastBiasMode # noqa
-
-__all__ = ['StandaloneImageViewer']
-
-
-class StandaloneImageViewer(QtWidgets.QMainWindow):
- """
- A simplified image viewer, without any brushing or linking,
- but with the ability to adjust contrast and resample.
- """
- window_closed = QtCore.Signal()
- _toolbar_cls = BasicToolbar
- tools = ['image:contrast', 'image:colormap']
-
- def __init__(self, image=None, wcs=None, parent=None, **kwargs):
- """
- :param image: Image to display (2D numpy array)
- :param parent: Parent widget (optional)
-
- :param kwargs: Extra keywords to pass to imshow
- """
- super(StandaloneImageViewer, self).__init__(parent)
-
- self.central_widget = MplWidget()
- self.setCentralWidget(self.central_widget)
- self._setup_axes()
-
- self._composite = CompositeArray()
- self._composite.allocate('image')
-
- self._im = None
-
- self.initialize_toolbar()
-
- if image is not None:
- self.set_image(image=image, wcs=wcs, **kwargs)
-
- def _setup_axes(self):
- _, self._axes = init_mpl(self.central_widget.canvas.fig, axes=None, wcs=True)
- self._axes.set_aspect('equal', adjustable='datalim')
-
- @defer_draw
- def set_image(self, image=None, wcs=None, **kwargs):
- """
- Update the image shown in the widget
- """
- if self._im is not None:
- self._im.remove()
- self._im = None
-
- kwargs.setdefault('origin', 'upper')
-
- self._composite.set('image', array=image, color=colormaps.members[0][1])
- self._im = imshow(self._axes, self._composite, **kwargs)
- self._im_array = image
- self._set_norm(self._contrast_mode)
-
- if 'extent' in kwargs:
- self.axes.set_xlim(kwargs['extent'][:2])
- self.axes.set_ylim(kwargs['extent'][2:])
- else:
- ny, nx = image.shape
- self.axes.set_xlim(-0.5, nx - 0.5)
- self.axes.set_ylim(-0.5, ny - 0.5)
-
- # FIXME: for a reason I don't quite understand, dataLim doesn't
- # get updated immediately here, which means that there are then
- # issues in the first draw of the image (the limits are such that
- # only part of the image is shown). We just set dataLim manually
- # to avoid this issue. This is also done in ImageViewer.
- self.axes.dataLim.intervalx = self.axes.get_xlim()
- self.axes.dataLim.intervaly = self.axes.get_ylim()
-
- self._redraw()
-
- @property
- def axes(self):
- """
- The Matplotlib axes object for this figure
- """
- return self._axes
-
- def show(self):
- super(StandaloneImageViewer, self).show()
- self._redraw()
-
- def _redraw(self):
- self.central_widget.canvas.draw_idle()
-
- def set_cmap(self, cmap):
- self._composite.set('image', color=cmap)
- self._im.invalidate_cache()
- self._redraw()
-
- def mdi_wrap(self):
- """
- Embed this widget in a GlueMdiSubWindow
- """
- from glue.app.qt.mdi_area import GlueMdiSubWindow
- sub = GlueMdiSubWindow()
- sub.setWidget(self)
- self.destroyed.connect(sub.close)
- self.window_closed.connect(sub.close)
- sub.resize(self.size())
- self._mdi_wrapper = sub
- return sub
-
- def closeEvent(self, event):
- if self._im is not None:
- self._im.remove()
- self._im = None
- self.window_closed.emit()
- return super(StandaloneImageViewer, self).closeEvent(event)
-
- def _set_norm(self, mode):
- """
- Use the `ContrastMouseMode` to adjust the transfer function
- """
-
- pmin, pmax = mode.get_clip_percentile()
-
- if pmin is None:
- clim = mode.get_vmin_vmax()
- else:
- clim = (np.nanpercentile(self._im_array, pmin),
- np.nanpercentile(self._im_array, pmax))
-
- stretch = mode.stretch
- self._composite.set('image', clim=clim, stretch=stretch,
- bias=mode.bias, contrast=mode.contrast)
-
- self._im.invalidate_cache()
- self._redraw()
-
- def initialize_toolbar(self):
-
- from glue.config import viewer_tool
-
- self.toolbar = self._toolbar_cls(self)
-
- for tool_id in self.tools:
- mode_cls = viewer_tool.members[tool_id]
- if tool_id == 'image:contrast':
- mode = mode_cls(self, move_callback=self._set_norm)
- self._contrast_mode = mode
- else:
- mode = mode_cls(self)
- self.toolbar.add_tool(mode)
-
- self.addToolBar(self.toolbar)
-
- def set_status(self, message):
- sb = self.statusBar()
- sb.showMessage(message)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.image.qt.standalone_image_viewer is deprecated, use glue_qt.viewers.image.standalone_image_viewer instead', GlueDeprecationWarning)
+from glue_qt.viewers.image.standalone_image_viewer import * # noqa
diff --git a/glue/viewers/image/qt/tests/__init__.py b/glue/viewers/image/qt/tests/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/glue/viewers/image/qt/tests/baseline/test_resample_on_zoom.png b/glue/viewers/image/qt/tests/baseline/test_resample_on_zoom.png
deleted file mode 100644
index e1c507966..000000000
Binary files a/glue/viewers/image/qt/tests/baseline/test_resample_on_zoom.png and /dev/null differ
diff --git a/glue/viewers/image/qt/tests/data/image_cube_v0.glu b/glue/viewers/image/qt/tests/data/image_cube_v0.glu
deleted file mode 100644
index 4a5671bf4..000000000
--- a/glue/viewers/image/qt/tests/data/image_cube_v0.glu
+++ /dev/null
@@ -1,410 +0,0 @@
-{
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsIDQsIDIsIDUpLCB9ICAgIAoAAAAAAAAAAAEAAAAAAAAAAgAAAAAAAAADAAAAAAAAAAQAAAAAAAAABQAAAAAAAAAGAAAAAAAAAAcAAAAAAAAACAAAAAAAAAAJAAAAAAAAAAoAAAAAAAAACwAAAAAAAAAMAAAAAAAAAA0AAAAAAAAADgAAAAAAAAAPAAAAAAAAABAAAAAAAAAAEQAAAAAAAAASAAAAAAAAABMAAAAAAAAAFAAAAAAAAAAVAAAAAAAAABYAAAAAAAAAFwAAAAAAAAAYAAAAAAAAABkAAAAAAAAAGgAAAAAAAAAbAAAAAAAAABwAAAAAAAAAHQAAAAAAAAAeAAAAAAAAAB8AAAAAAAAAIAAAAAAAAAAhAAAAAAAAACIAAAAAAAAAIwAAAAAAAAAkAAAAAAAAACUAAAAAAAAAJgAAAAAAAAAnAAAAAAAAACgAAAAAAAAAKQAAAAAAAAAqAAAAAAAAACsAAAAAAAAALAAAAAAAAAAtAAAAAAAAAC4AAAAAAAAALwAAAAAAAAAwAAAAAAAAADEAAAAAAAAAMgAAAAAAAAAzAAAAAAAAADQAAAAAAAAANQAAAAAAAAA2AAAAAAAAADcAAAAAAAAAOAAAAAAAAAA5AAAAAAAAADoAAAAAAAAAOwAAAAAAAAA8AAAAAAAAAD0AAAAAAAAAPgAAAAAAAAA/AAAAAAAAAEAAAAAAAAAAQQAAAAAAAABCAAAAAAAAAEMAAAAAAAAARAAAAAAAAABFAAAAAAAAAEYAAAAAAAAARwAAAAAAAABIAAAAAAAAAEkAAAAAAAAASgAAAAAAAABLAAAAAAAAAEwAAAAAAAAATQAAAAAAAABOAAAAAAAAAE8AAAAAAAAAUAAAAAAAAABRAAAAAAAAAFIAAAAAAAAAUwAAAAAAAABUAAAAAAAAAFUAAAAAAAAAVgAAAAAAAABXAAAAAAAAAFgAAAAAAAAAWQAAAAAAAABaAAAAAAAAAFsAAAAAAAAAXAAAAAAAAABdAAAAAAAAAF4AAAAAAAAAXwAAAAAAAABgAAAAAAAAAGEAAAAAAAAAYgAAAAAAAABjAAAAAAAAAGQAAAAAAAAAZQAAAAAAAABmAAAAAAAAAGcAAAAAAAAAaAAAAAAAAABpAAAAAAAAAGoAAAAAAAAAawAAAAAAAABsAAAAAAAAAG0AAAAAAAAAbgAAAAAAAABvAAAAAAAAAHAAAAAAAAAAcQAAAAAAAAByAAAAAAAAAHMAAAAAAAAAdAAAAAAAAAB1AAAAAAAAAHYAAAAAAAAAdwAAAAAAAAA="
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "index": 1,
- "pix2world": false,
- "to": [
- "Pixel Axis 1"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3"
- ],
- "index": 2,
- "pix2world": true,
- "to": [
- "World 2"
- ]
- },
- "CoordinateComponentLink_1": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "index": 2,
- "pix2world": false,
- "to": [
- "Pixel Axis 2"
- ]
- },
- "CoordinateComponentLink_2": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3"
- ],
- "index": 3,
- "pix2world": true,
- "to": [
- "World 3"
- ]
- },
- "CoordinateComponentLink_3": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "index": 3,
- "pix2world": false,
- "to": [
- "Pixel Axis 3"
- ]
- },
- "CoordinateComponentLink_4": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponentLink_5": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0"
- ]
- },
- "CoordinateComponentLink_6": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3"
- ],
- "index": 1,
- "pix2world": true,
- "to": [
- "World 1"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": false
- },
- "CoordinateComponent_1": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 2,
- "world": false
- },
- "CoordinateComponent_2": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 3,
- "world": false
- },
- "CoordinateComponent_3": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "CoordinateComponent_4": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": true
- },
- "CoordinateComponent_5": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 2,
- "world": true
- },
- "CoordinateComponent_6": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 3,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DS9Normalize": {
- "_type": "glue.viewers.image.ds9norm.DS9Normalize",
- "bias": 0.5,
- "clip_hi": 100,
- "clip_lo": 0,
- "contrast": 1.0,
- "stretch": "linear",
- "vmax": null,
- "vmin": null
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "array_0",
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3",
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "CoordinateComponent_1",
- "CoordinateComponent_2",
- "CoordinateComponent_3",
- "CoordinateComponent_4",
- "CoordinateComponent_5",
- "CoordinateComponent_6"
- ],
- "data": [
- "array"
- ],
- "groups": [],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0",
- "CoordinateComponentLink_1",
- "CoordinateComponentLink_2",
- "CoordinateComponentLink_3",
- "CoordinateComponentLink_4",
- "CoordinateComponentLink_5",
- "CoordinateComponentLink_6"
- ],
- "subset_group_count": 0
- },
- "ImageWidget": {
- "_type": "glue.viewers.image.qt.viewer_widget.ImageWidget",
- "layers": [
- {
- "_type": "glue.viewers.image.layer_artist.ImageLayerArtist",
- "layer": "array",
- "norm": "DS9Normalize",
- "visible": true,
- "zorder": 1
- }
- ],
- "pos": [
- 0,
- 0
- ],
- "properties": {
- "attribute": "array_0",
- "batt": null,
- "data": "array",
- "gatt": null,
- "ratt": null,
- "rgb_mode": false,
- "rgb_viz": [
- true,
- true,
- true
- ],
- "slice": [
- 2,
- "y",
- "x",
- 1
- ]
- },
- "session": "Session",
- "size": [
- 731,
- 529
- ]
- },
- "Pixel Axis 0": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0"
- },
- "Pixel Axis 1": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 1,
- "hidden": true,
- "label": "Pixel Axis 1"
- },
- "Pixel Axis 2": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 2,
- "hidden": true,
- "label": "Pixel Axis 2"
- },
- "Pixel Axis 3": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 3,
- "hidden": true,
- "label": "Pixel Axis 3"
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "World 1": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 1"
- },
- "World 2": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 2"
- },
- "World 3": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 3"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue.plugins.tools.pv_slicer",
- "glue.viewers.histogram",
- "glue.viewers.table",
- "glue_vispy_viewers.volume",
- "glue.plugins.exporters.plotly",
- "glue.plugins.export_d3po",
- "glue.viewers.image",
- "glue.plugins.tools.spectrum_tool",
- "glue_vispy_viewers.scatter",
- "glue.viewers.scatter",
- "glue.plugins.coordinate_helpers",
- "glue.core.data_exporters"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- [
- "ImageWidget"
- ]
- ]
- },
- "array": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "array_0",
- "Component"
- ],
- [
- "Pixel Axis 0",
- "CoordinateComponent"
- ],
- [
- "Pixel Axis 1",
- "CoordinateComponent_0"
- ],
- [
- "Pixel Axis 2",
- "CoordinateComponent_1"
- ],
- [
- "Pixel Axis 3",
- "CoordinateComponent_2"
- ],
- [
- "World 0",
- "CoordinateComponent_3"
- ],
- [
- "World 1",
- "CoordinateComponent_4"
- ],
- [
- "World 2",
- "CoordinateComponent_5"
- ],
- [
- "World 3",
- "CoordinateComponent_6"
- ]
- ],
- "coords": "Coordinates",
- "label": "array",
- "primary_owner": [
- "array_0",
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3",
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "0.35",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [],
- "uuid": "5e2335ce-5613-4fb1-aa58-1cf342f7b755"
- },
- "array_0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "array"
- }
-}
\ No newline at end of file
diff --git a/glue/viewers/image/qt/tests/data/image_cube_v1.glu b/glue/viewers/image/qt/tests/data/image_cube_v1.glu
deleted file mode 100644
index fef3667c4..000000000
--- a/glue/viewers/image/qt/tests/data/image_cube_v1.glu
+++ /dev/null
@@ -1,562 +0,0 @@
-{
- "CallbackList": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ImageLayerState"
- ]
- },
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsIDQsIDIsIDUpLCB9ICAgIAoAAAAAAAAAAAEAAAAAAAAAAgAAAAAAAAADAAAAAAAAAAQAAAAAAAAABQAAAAAAAAAGAAAAAAAAAAcAAAAAAAAACAAAAAAAAAAJAAAAAAAAAAoAAAAAAAAACwAAAAAAAAAMAAAAAAAAAA0AAAAAAAAADgAAAAAAAAAPAAAAAAAAABAAAAAAAAAAEQAAAAAAAAASAAAAAAAAABMAAAAAAAAAFAAAAAAAAAAVAAAAAAAAABYAAAAAAAAAFwAAAAAAAAAYAAAAAAAAABkAAAAAAAAAGgAAAAAAAAAbAAAAAAAAABwAAAAAAAAAHQAAAAAAAAAeAAAAAAAAAB8AAAAAAAAAIAAAAAAAAAAhAAAAAAAAACIAAAAAAAAAIwAAAAAAAAAkAAAAAAAAACUAAAAAAAAAJgAAAAAAAAAnAAAAAAAAACgAAAAAAAAAKQAAAAAAAAAqAAAAAAAAACsAAAAAAAAALAAAAAAAAAAtAAAAAAAAAC4AAAAAAAAALwAAAAAAAAAwAAAAAAAAADEAAAAAAAAAMgAAAAAAAAAzAAAAAAAAADQAAAAAAAAANQAAAAAAAAA2AAAAAAAAADcAAAAAAAAAOAAAAAAAAAA5AAAAAAAAADoAAAAAAAAAOwAAAAAAAAA8AAAAAAAAAD0AAAAAAAAAPgAAAAAAAAA/AAAAAAAAAEAAAAAAAAAAQQAAAAAAAABCAAAAAAAAAEMAAAAAAAAARAAAAAAAAABFAAAAAAAAAEYAAAAAAAAARwAAAAAAAABIAAAAAAAAAEkAAAAAAAAASgAAAAAAAABLAAAAAAAAAEwAAAAAAAAATQAAAAAAAABOAAAAAAAAAE8AAAAAAAAAUAAAAAAAAABRAAAAAAAAAFIAAAAAAAAAUwAAAAAAAABUAAAAAAAAAFUAAAAAAAAAVgAAAAAAAABXAAAAAAAAAFgAAAAAAAAAWQAAAAAAAABaAAAAAAAAAFsAAAAAAAAAXAAAAAAAAABdAAAAAAAAAF4AAAAAAAAAXwAAAAAAAABgAAAAAAAAAGEAAAAAAAAAYgAAAAAAAABjAAAAAAAAAGQAAAAAAAAAZQAAAAAAAABmAAAAAAAAAGcAAAAAAAAAaAAAAAAAAABpAAAAAAAAAGoAAAAAAAAAawAAAAAAAABsAAAAAAAAAG0AAAAAAAAAbgAAAAAAAABvAAAAAAAAAHAAAAAAAAAAcQAAAAAAAAByAAAAAAAAAHMAAAAAAAAAdAAAAAAAAAB1AAAAAAAAAHYAAAAAAAAAdwAAAAAAAAA="
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "index": 2,
- "pix2world": false,
- "to": [
- "Pixel Axis 2"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "index": 3,
- "pix2world": false,
- "to": [
- "Pixel Axis 3"
- ]
- },
- "CoordinateComponentLink_1": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "index": 2,
- "pix2world": false,
- "to": [
- "Pixel Axis 2"
- ]
- },
- "CoordinateComponentLink_10": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3"
- ],
- "index": 1,
- "pix2world": true,
- "to": [
- "World 1"
- ]
- },
- "CoordinateComponentLink_11": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3"
- ],
- "index": 2,
- "pix2world": true,
- "to": [
- "World 2"
- ]
- },
- "CoordinateComponentLink_12": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0"
- ]
- },
- "CoordinateComponentLink_13": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3"
- ],
- "index": 1,
- "pix2world": true,
- "to": [
- "World 1"
- ]
- },
- "CoordinateComponentLink_14": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponentLink_2": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "index": 3,
- "pix2world": false,
- "to": [
- "Pixel Axis 3"
- ]
- },
- "CoordinateComponentLink_3": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0"
- ]
- },
- "CoordinateComponentLink_4": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3"
- ],
- "index": 2,
- "pix2world": true,
- "to": [
- "World 2"
- ]
- },
- "CoordinateComponentLink_5": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponentLink_6": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3"
- ],
- "index": 3,
- "pix2world": true,
- "to": [
- "World 3"
- ]
- },
- "CoordinateComponentLink_7": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "index": 1,
- "pix2world": false,
- "to": [
- "Pixel Axis 1"
- ]
- },
- "CoordinateComponentLink_8": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3"
- ],
- "index": 3,
- "pix2world": true,
- "to": [
- "World 3"
- ]
- },
- "CoordinateComponentLink_9": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "index": 1,
- "pix2world": false,
- "to": [
- "Pixel Axis 1"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": false
- },
- "CoordinateComponent_1": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 2,
- "world": false
- },
- "CoordinateComponent_2": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 3,
- "world": false
- },
- "CoordinateComponent_3": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "CoordinateComponent_4": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": true
- },
- "CoordinateComponent_5": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 2,
- "world": true
- },
- "CoordinateComponent_6": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 3,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "array_0",
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3",
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "CoordinateComponent_1",
- "CoordinateComponent_2",
- "CoordinateComponent_3",
- "CoordinateComponent_4",
- "CoordinateComponent_5",
- "CoordinateComponent_6"
- ],
- "data": [
- "array"
- ],
- "groups": [],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0",
- "CoordinateComponentLink_1",
- "CoordinateComponentLink_2",
- "CoordinateComponentLink_3",
- "CoordinateComponentLink_4",
- "CoordinateComponentLink_5",
- "CoordinateComponentLink_6",
- "CoordinateComponentLink_7",
- "CoordinateComponentLink_8",
- "CoordinateComponentLink_9",
- "CoordinateComponentLink_10",
- "CoordinateComponentLink_11",
- "CoordinateComponentLink_12",
- "CoordinateComponentLink_13",
- "CoordinateComponentLink_14"
- ],
- "subset_group_count": 0
- },
- "ImageLayerState": {
- "_type": "glue.viewers.image.state.ImageLayerState",
- "values": {
- "alpha": 0.8,
- "attribute": "array_0",
- "bias": 0.5,
- "cmap": "LinearSegmentedColormap",
- "color": "st__0.35",
- "contrast": 1.0,
- "global_sync": true,
- "layer": "array",
- "percentile": 100,
- "stretch": "st__linear",
- "v_max": 119.0,
- "v_min": 0.0,
- "visible": true,
- "zorder": 2
- }
- },
- "ImageViewer": {
- "_protocol": 1,
- "_type": "glue.viewers.image.qt.data_viewer.ImageViewer",
- "layers": [
- {
- "_type": "glue.viewers.image.layer_artist.ImageLayerArtist",
- "state": "ImageLayerState"
- }
- ],
- "pos": [
- 0,
- 0
- ],
- "session": "Session",
- "size": [
- 731,
- 529
- ],
- "state": {
- "values": {
- "aspect": "st__equal",
- "color_mode": "st__Colormaps",
- "layers": "CallbackList",
- "reference_data": "array",
- "slices": [
- 2,
- 0,
- 0,
- 1
- ],
- "x_att": "Pixel Axis 2",
- "x_att_world": "World 2",
- "x_log": false,
- "x_max": 4.075455766965458,
- "x_min": -2.932007545418843,
- "y_att": "Pixel Axis 1",
- "y_att_world": "World 1",
- "y_log": false,
- "y_max": 3.6720458592035916,
- "y_min": -0.6781873651245816
- }
- }
- },
- "LinearSegmentedColormap": {
- "_type": "matplotlib.colors.LinearSegmentedColormap",
- "cmap": "gray"
- },
- "Pixel Axis 0": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0"
- },
- "Pixel Axis 1": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 1,
- "hidden": true,
- "label": "Pixel Axis 1"
- },
- "Pixel Axis 2": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 2,
- "hidden": true,
- "label": "Pixel Axis 2"
- },
- "Pixel Axis 3": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 3,
- "hidden": true,
- "label": "Pixel Axis 3"
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "World 1": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 1"
- },
- "World 2": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 2"
- },
- "World 3": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 3"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue.viewers.scatter",
- "glue.viewers.table",
- "glue_medical",
- "specviz.app",
- "glue.plugins.exporters.plotly",
- "glue.core.data_exporters",
- "glue.plugins.export_d3po",
- "glue_vispy_viewers.volume",
- "glue.plugins.tools.spectrum_tool",
- "glue.plugins.coordinate_helpers",
- "glue.viewers.histogram",
- "glue.plugins.tools.pv_slicer",
- "glue_vispy_viewers.scatter",
- "glue.viewers.image"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- [
- "ImageViewer"
- ]
- ]
- },
- "array": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "array_0",
- "Component"
- ],
- [
- "Pixel Axis 0",
- "CoordinateComponent"
- ],
- [
- "Pixel Axis 1",
- "CoordinateComponent_0"
- ],
- [
- "Pixel Axis 2",
- "CoordinateComponent_1"
- ],
- [
- "Pixel Axis 3",
- "CoordinateComponent_2"
- ],
- [
- "World 0",
- "CoordinateComponent_3"
- ],
- [
- "World 1",
- "CoordinateComponent_4"
- ],
- [
- "World 2",
- "CoordinateComponent_5"
- ],
- [
- "World 3",
- "CoordinateComponent_6"
- ]
- ],
- "coords": "Coordinates",
- "label": "array",
- "primary_owner": [
- "array_0",
- "Pixel Axis 0",
- "Pixel Axis 1",
- "Pixel Axis 2",
- "Pixel Axis 3",
- "World 0",
- "World 1",
- "World 2",
- "World 3"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "0.35",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [],
- "uuid": "5e2335ce-5613-4fb1-aa58-1cf342f7b755"
- },
- "array_0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "array"
- }
-}
\ No newline at end of file
diff --git a/glue/viewers/image/qt/tests/data/image_rgb_v0.glu b/glue/viewers/image/qt/tests/data/image_rgb_v0.glu
deleted file mode 100644
index 167ce8a1e..000000000
--- a/glue/viewers/image/qt/tests/data/image_rgb_v0.glu
+++ /dev/null
@@ -1,337 +0,0 @@
-{
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDIsIDIpLCB9ICAgICAgICAgIAoAAAAAAAAAAAEAAAAAAAAAAgAAAAAAAAADAAAAAAAAAA=="
- },
- "units": ""
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDIsIDIpLCB9ICAgICAgICAgIAoIAAAAAAAAAAkAAAAAAAAACgAAAAAAAAALAAAAAAAAAA=="
- },
- "units": ""
- },
- "Component_1": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDIsIDIpLCB9ICAgICAgICAgIAoEAAAAAAAAAAUAAAAAAAAABgAAAAAAAAAHAAAAAAAAAA=="
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1"
- ],
- "index": 1,
- "pix2world": false,
- "to": [
- "Pixel Axis 1 [x]"
- ]
- },
- "CoordinateComponentLink_1": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [y]"
- ]
- },
- "CoordinateComponentLink_2": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]"
- ],
- "index": 1,
- "pix2world": true,
- "to": [
- "World 1"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": false
- },
- "CoordinateComponent_1": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "CoordinateComponent_2": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DS9Normalize": {
- "_type": "glue.viewers.image.ds9norm.DS9Normalize",
- "bias": 0.5,
- "clip_hi": null,
- "clip_lo": null,
- "contrast": 1.0,
- "stretch": "arcsinh",
- "vmax": 3,
- "vmin": 0
- },
- "DS9Normalize_0": {
- "_type": "glue.viewers.image.ds9norm.DS9Normalize",
- "bias": 0.5,
- "clip_hi": 99,
- "clip_lo": 1,
- "contrast": 1.0,
- "stretch": "linear",
- "vmax": null,
- "vmin": null
- },
- "DS9Normalize_1": {
- "_type": "glue.viewers.image.ds9norm.DS9Normalize",
- "bias": 0.5,
- "clip_hi": null,
- "clip_lo": null,
- "contrast": 1.0,
- "stretch": "linear",
- "vmax": 5.0,
- "vmin": -5.0
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "a",
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]",
- "World 0",
- "World 1",
- "c",
- "b"
- ],
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "CoordinateComponent_1",
- "CoordinateComponent_2",
- "Component_0",
- "Component_1"
- ],
- "data": [
- "rgbcube"
- ],
- "groups": [],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0",
- "CoordinateComponentLink_1",
- "CoordinateComponentLink_2"
- ],
- "subset_group_count": 0
- },
- "ImageWidget": {
- "_type": "glue.viewers.image.qt.viewer_widget.ImageWidget",
- "layers": [
- {
- "_type": "glue.viewers.image.layer_artist.RGBImageLayerArtist",
- "b": "b",
- "bnorm": "DS9Normalize",
- "color_visible": [
- true,
- false,
- true
- ],
- "g": "c",
- "gnorm": "DS9Normalize_0",
- "layer": "rgbcube",
- "norm": "DS9Normalize_0",
- "r": "a",
- "rnorm": "DS9Normalize_1",
- "visible": true,
- "zorder": 1
- }
- ],
- "pos": [
- 0,
- 0
- ],
- "properties": {
- "attribute": "a",
- "batt": "b",
- "data": "rgbcube",
- "gatt": "c",
- "ratt": "a",
- "rgb_mode": true,
- "rgb_viz": [
- true,
- false,
- true
- ],
- "slice": [
- "y",
- "x"
- ]
- },
- "session": "Session",
- "size": [
- 600,
- 400
- ]
- },
- "Pixel Axis 0 [y]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [y]"
- },
- "Pixel Axis 1 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 1,
- "hidden": true,
- "label": "Pixel Axis 1 [x]"
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "World 1": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 1"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue.plugins.tools.pv_slicer",
- "glue.viewers.histogram",
- "glue.viewers.table",
- "glue_vispy_viewers.volume",
- "glue.plugins.exporters.plotly",
- "glue.plugins.export_d3po",
- "glue.viewers.image",
- "glue.plugins.tools.spectrum_tool",
- "glue_vispy_viewers.scatter",
- "glue.viewers.scatter",
- "glue.plugins.coordinate_helpers",
- "glue.core.data_exporters"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- [
- "ImageWidget"
- ]
- ]
- },
- "a": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "a"
- },
- "b": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "b"
- },
- "c": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "c"
- },
- "rgbcube": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "a",
- "Component"
- ],
- [
- "Pixel Axis 0 [y]",
- "CoordinateComponent"
- ],
- [
- "Pixel Axis 1 [x]",
- "CoordinateComponent_0"
- ],
- [
- "World 0",
- "CoordinateComponent_1"
- ],
- [
- "World 1",
- "CoordinateComponent_2"
- ],
- [
- "c",
- "Component_0"
- ],
- [
- "b",
- "Component_1"
- ]
- ],
- "coords": "Coordinates",
- "label": "rgbcube",
- "primary_owner": [
- "a",
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]",
- "World 0",
- "World 1",
- "c",
- "b"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "0.35",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [],
- "uuid": "d2fdde54-ab42-4370-9670-4b9906da51f2"
- }
-}
\ No newline at end of file
diff --git a/glue/viewers/image/qt/tests/data/image_rgb_v1.glu b/glue/viewers/image/qt/tests/data/image_rgb_v1.glu
deleted file mode 100644
index 7bd2a3b4f..000000000
--- a/glue/viewers/image/qt/tests/data/image_rgb_v1.glu
+++ /dev/null
@@ -1,434 +0,0 @@
-{
- "CallbackList": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ImageLayerState",
- "ImageLayerState_0",
- "ImageLayerState_1"
- ]
- },
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDIsIDIpLCB9ICAgICAgICAgIAoAAAAAAAAAAAEAAAAAAAAAAgAAAAAAAAADAAAAAAAAAA=="
- },
- "units": ""
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDIsIDIpLCB9ICAgICAgICAgIAoIAAAAAAAAAAkAAAAAAAAACgAAAAAAAAALAAAAAAAAAA=="
- },
- "units": ""
- },
- "Component_1": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDIsIDIpLCB9ICAgICAgICAgIAoEAAAAAAAAAAUAAAAAAAAABgAAAAAAAAAHAAAAAAAAAA=="
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]"
- ],
- "index": 1,
- "pix2world": true,
- "to": [
- "World 1"
- ]
- },
- "CoordinateComponentLink_1": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1"
- ],
- "index": 1,
- "pix2world": false,
- "to": [
- "Pixel Axis 1 [x]"
- ]
- },
- "CoordinateComponentLink_2": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponentLink_3": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [y]"
- ]
- },
- "CoordinateComponentLink_4": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]"
- ],
- "index": 1,
- "pix2world": true,
- "to": [
- "World 1"
- ]
- },
- "CoordinateComponentLink_5": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1"
- ],
- "index": 1,
- "pix2world": false,
- "to": [
- "Pixel Axis 1 [x]"
- ]
- },
- "CoordinateComponentLink_6": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [y]"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": false
- },
- "CoordinateComponent_1": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "CoordinateComponent_2": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "a",
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]",
- "World 0",
- "World 1",
- "c",
- "b"
- ],
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "CoordinateComponent_1",
- "CoordinateComponent_2",
- "Component_0",
- "Component_1"
- ],
- "data": [
- "rgbcube"
- ],
- "groups": [],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0",
- "CoordinateComponentLink_1",
- "CoordinateComponentLink_2",
- "CoordinateComponentLink_3",
- "CoordinateComponentLink_4",
- "CoordinateComponentLink_5",
- "CoordinateComponentLink_6"
- ],
- "subset_group_count": 0
- },
- "ImageLayerState": {
- "_type": "glue.viewers.image.state.ImageLayerState",
- "values": {
- "alpha": 0.8,
- "attribute": "a",
- "bias": 0.5,
- "cmap": "LinearSegmentedColormap",
- "color": "st__r",
- "contrast": 1.0,
- "global_sync": false,
- "layer": "rgbcube",
- "percentile": "st__Custom",
- "stretch": "st__linear",
- "v_max": 5.0,
- "v_min": -5.0,
- "visible": true,
- "zorder": 2
- }
- },
- "ImageLayerState_0": {
- "_type": "glue.viewers.image.state.ImageLayerState",
- "values": {
- "alpha": 0.8,
- "attribute": "c",
- "bias": 0.5,
- "cmap": "LinearSegmentedColormap",
- "color": "st__g",
- "contrast": 1.0,
- "global_sync": false,
- "layer": "rgbcube",
- "percentile": 99,
- "stretch": "st__linear",
- "v_max": 10.985,
- "v_min": 8.015,
- "visible": false,
- "zorder": 3
- }
- },
- "ImageLayerState_1": {
- "_type": "glue.viewers.image.state.ImageLayerState",
- "values": {
- "alpha": 0.8,
- "attribute": "b",
- "bias": 0.5,
- "cmap": "LinearSegmentedColormap",
- "color": "st__b",
- "contrast": 1.0,
- "global_sync": false,
- "layer": "rgbcube",
- "percentile": "st__Custom",
- "stretch": "st__arcsinh",
- "v_max": 3,
- "v_min": 0,
- "visible": true,
- "zorder": 4
- }
- },
- "ImageViewer": {
- "_protocol": 1,
- "_type": "glue.viewers.image.qt.data_viewer.ImageViewer",
- "layers": [
- {
- "_type": "glue.viewers.image.layer_artist.ImageLayerArtist",
- "state": "ImageLayerState"
- },
- {
- "_type": "glue.viewers.image.layer_artist.ImageLayerArtist",
- "state": "ImageLayerState_0"
- },
- {
- "_type": "glue.viewers.image.layer_artist.ImageLayerArtist",
- "state": "ImageLayerState_1"
- }
- ],
- "pos": [
- 0,
- 0
- ],
- "session": "Session",
- "size": [
- 600,
- 400
- ],
- "state": {
- "values": {
- "aspect": "st__equal",
- "color_mode": "st__One color per layer",
- "layers": "CallbackList",
- "reference_data": "rgbcube",
- "slices": [
- 0,
- 0
- ],
- "x_att": "Pixel Axis 1 [x]",
- "x_att_world": "World 1",
- "x_log": false,
- "x_max": 2.5253556681900653,
- "x_min": -1.4613891239424421,
- "y_att": "Pixel Axis 0 [y]",
- "y_att_world": "World 0",
- "y_log": false,
- "y_max": 1.555040949314538,
- "y_min": -0.5351753331368783
- }
- }
- },
- "LinearSegmentedColormap": {
- "_type": "matplotlib.colors.LinearSegmentedColormap",
- "cmap": "gray"
- },
- "Pixel Axis 0 [y]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [y]"
- },
- "Pixel Axis 1 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 1,
- "hidden": true,
- "label": "Pixel Axis 1 [x]"
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "World 1": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 1"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue.core.data_exporters",
- "glue.viewers.image",
- "glue.viewers.scatter",
- "glue_vispy_viewers.volume",
- "glue_medical",
- "glue.plugins.tools.pv_slicer",
- "glue.plugins.coordinate_helpers",
- "glue.viewers.table",
- "glue_vispy_viewers.scatter",
- "glue.plugins.export_d3po",
- "glue.viewers.histogram",
- "glue.plugins.tools.spectrum_tool",
- "glue.plugins.exporters.plotly",
- "specviz.app"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- [
- "ImageViewer"
- ]
- ]
- },
- "a": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "a"
- },
- "b": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "b"
- },
- "c": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "c"
- },
- "rgbcube": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "a",
- "Component"
- ],
- [
- "Pixel Axis 0 [y]",
- "CoordinateComponent"
- ],
- [
- "Pixel Axis 1 [x]",
- "CoordinateComponent_0"
- ],
- [
- "World 0",
- "CoordinateComponent_1"
- ],
- [
- "World 1",
- "CoordinateComponent_2"
- ],
- [
- "c",
- "Component_0"
- ],
- [
- "b",
- "Component_1"
- ]
- ],
- "coords": "Coordinates",
- "label": "rgbcube",
- "primary_owner": [
- "a",
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]",
- "World 0",
- "World 1",
- "c",
- "b"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "0.35",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [],
- "uuid": "d2fdde54-ab42-4370-9670-4b9906da51f2"
- }
-}
\ No newline at end of file
diff --git a/glue/viewers/image/qt/tests/data/image_v0.glu b/glue/viewers/image/qt/tests/data/image_v0.glu
deleted file mode 100644
index 7c1716413..000000000
--- a/glue/viewers/image/qt/tests/data/image_v0.glu
+++ /dev/null
@@ -1,724 +0,0 @@
-{
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDIsIDIpLCB9ICAgICAgICAgIAoBAAAAAAAAAAIAAAAAAAAAAwAAAAAAAAAEAAAAAAAAAA=="
- },
- "units": ""
- },
- "ComponentLink": {
- "_type": "glue.core.component_link.ComponentLink",
- "frm": [
- "World 0"
- ],
- "hidden": false,
- "inverse": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- },
- "to": [
- "a"
- ],
- "using": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- }
- },
- "ComponentLink_0": {
- "_type": "glue.core.component_link.ComponentLink",
- "frm": [
- "World 1"
- ],
- "hidden": false,
- "inverse": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- },
- "to": [
- "b"
- ],
- "using": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- }
- },
- "ComponentLink_1": {
- "_type": "glue.core.component_link.ComponentLink",
- "frm": [
- "b"
- ],
- "hidden": false,
- "inverse": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- },
- "to": [
- "World 1"
- ],
- "using": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- }
- },
- "ComponentLink_2": {
- "_type": "glue.core.component_link.ComponentLink",
- "frm": [
- "a"
- ],
- "hidden": false,
- "inverse": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- },
- "to": [
- "World 0"
- ],
- "using": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- }
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGY4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDIsKSwgfSAgICAgICAgICAgIAoAAAAAAAD4PwAAAAAAAABA"
- },
- "units": ""
- },
- "Component_1": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGY4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDIsKSwgfSAgICAgICAgICAgIAoAAAAAAADgPwAAAAAAAABA"
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates_0",
- "frm": [
- "World 0_0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]"
- ]
- },
- "CoordinateComponentLink_1": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]"
- ],
- "index": 1,
- "pix2world": true,
- "to": [
- "World 1"
- ]
- },
- "CoordinateComponentLink_2": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1"
- ],
- "index": 1,
- "pix2world": false,
- "to": [
- "Pixel Axis 1 [x]"
- ]
- },
- "CoordinateComponentLink_3": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [y]"
- ]
- },
- "CoordinateComponentLink_4": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates_0",
- "frm": [
- "Pixel Axis 0 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0_0"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": false
- },
- "CoordinateComponent_1": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "CoordinateComponent_2": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": true
- },
- "CoordinateComponent_3": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponent_4": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "Coordinates_0": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DS9Normalize": {
- "_type": "glue.viewers.image.ds9norm.DS9Normalize",
- "bias": 0.5,
- "clip_hi": 99.0,
- "clip_lo": 1.0,
- "contrast": 1.0,
- "stretch": "sqrt",
- "vmax": null,
- "vmin": null
- },
- "DS9Normalize_0": {
- "_type": "glue.viewers.image.ds9norm.DS9Normalize",
- "bias": 0.5,
- "clip_hi": null,
- "clip_lo": null,
- "contrast": 1.0,
- "stretch": "linear",
- "vmax": 2.0,
- "vmin": -2.0
- },
- "DS9Normalize_1": {
- "_type": "glue.viewers.image.ds9norm.DS9Normalize",
- "bias": 0.5,
- "clip_hi": null,
- "clip_lo": null,
- "contrast": 1.0,
- "stretch": "arcsinh",
- "vmax": 4,
- "vmin": 1
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "data1_0",
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]",
- "World 0",
- "World 1",
- "a",
- "b",
- "a",
- "Pixel Axis 0 [x]",
- "World 0_0",
- "b",
- "Pixel Axis 1 [x]",
- "World 1",
- "Pixel Axis 0 [y]",
- "World 0"
- ],
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "CoordinateComponent_1",
- "CoordinateComponent_2",
- "DerivedComponent",
- "DerivedComponent_0",
- "Component_0",
- "CoordinateComponent_3",
- "CoordinateComponent_4",
- "Component_1",
- "DerivedComponent_1",
- "DerivedComponent_2",
- "DerivedComponent_3",
- "DerivedComponent_4"
- ],
- "data": [
- "data1",
- "data2"
- ],
- "groups": [
- "Subset 1"
- ],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0",
- "CoordinateComponentLink_1",
- "ComponentLink",
- "CoordinateComponentLink_2",
- "CoordinateComponentLink_3",
- "ComponentLink_0",
- "CoordinateComponentLink_4"
- ],
- "subset_group_count": 1
- },
- "DerivedComponent": {
- "_type": "glue.core.component.DerivedComponent",
- "link": "ComponentLink"
- },
- "DerivedComponent_0": {
- "_type": "glue.core.component.DerivedComponent",
- "link": "ComponentLink_0"
- },
- "DerivedComponent_1": {
- "_type": "glue.core.component.DerivedComponent",
- "link": "CoordinateComponentLink_2"
- },
- "DerivedComponent_2": {
- "_type": "glue.core.component.DerivedComponent",
- "link": "ComponentLink_1"
- },
- "DerivedComponent_3": {
- "_type": "glue.core.component.DerivedComponent",
- "link": "CoordinateComponentLink_3"
- },
- "DerivedComponent_4": {
- "_type": "glue.core.component.DerivedComponent",
- "link": "ComponentLink_2"
- },
- "ImageWidget": {
- "_type": "glue.viewers.image.qt.viewer_widget.ImageWidget",
- "layers": [
- {
- "_type": "glue.viewers.image.layer_artist.ImageLayerArtist",
- "layer": "data1",
- "norm": "DS9Normalize",
- "visible": true,
- "zorder": 1
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "layer": "data2",
- "visible": true,
- "xatt": "Pixel Axis 1 [x]",
- "yatt": "Pixel Axis 0 [y]",
- "zorder": 2
- },
- {
- "_type": "glue.viewers.image.layer_artist.SubsetImageLayerArtist",
- "layer": "Subset 1_0",
- "visible": false,
- "zorder": 3
- }
- ],
- "pos": [
- -1,
- 1
- ],
- "properties": {
- "attribute": "data1_0",
- "batt": null,
- "data": "data1",
- "gatt": null,
- "ratt": null,
- "rgb_mode": false,
- "rgb_viz": [
- true,
- true,
- true
- ],
- "slice": [
- "y",
- "x"
- ]
- },
- "session": "Session",
- "size": [
- 568,
- 490
- ]
- },
- "ImageWidget_0": {
- "_type": "glue.viewers.image.qt.viewer_widget.ImageWidget",
- "layers": [
- {
- "_type": "glue.viewers.image.layer_artist.ImageLayerArtist",
- "layer": "data1",
- "norm": "DS9Normalize_1",
- "visible": true,
- "zorder": 1
- },
- {
- "_type": "glue.viewers.image.layer_artist.SubsetImageLayerArtist",
- "layer": "Subset 1_0",
- "visible": true,
- "zorder": 2
- }
- ],
- "pos": [
- 568,
- 1
- ],
- "properties": {
- "attribute": "data1_0",
- "batt": null,
- "data": "data1",
- "gatt": null,
- "ratt": null,
- "rgb_mode": false,
- "rgb_viz": [
- true,
- true,
- true
- ],
- "slice": [
- "y",
- "x"
- ]
- },
- "session": "Session",
- "size": [
- 606,
- 489
- ]
- },
- "ImageWidget_1": {
- "_type": "glue.viewers.image.qt.viewer_widget.ImageWidget",
- "layers": [
- {
- "_type": "glue.viewers.image.layer_artist.ImageLayerArtist",
- "layer": "data1",
- "norm": "DS9Normalize_0",
- "visible": true,
- "zorder": 1
- },
- {
- "_type": "glue.viewers.image.layer_artist.SubsetImageLayerArtist",
- "layer": "Subset 1_0",
- "visible": true,
- "zorder": 2
- }
- ],
- "pos": [
- 568,
- 487
- ],
- "properties": {
- "attribute": "data1_0",
- "batt": null,
- "data": "data1",
- "gatt": null,
- "ratt": null,
- "rgb_mode": false,
- "rgb_viz": [
- true,
- true,
- true
- ],
- "slice": [
- "y",
- "x"
- ]
- },
- "session": "Session",
- "size": [
- 600,
- 400
- ]
- },
- "Pixel Axis 0 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [x]"
- },
- "Pixel Axis 0 [y]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [y]"
- },
- "Pixel Axis 1 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 1,
- "hidden": true,
- "label": "Pixel Axis 1 [x]"
- },
- "PolygonalROI": {
- "_type": "glue.core.roi.PolygonalROI",
- "vx": [
- 0.7380952380952381,
- 1.847619047619048,
- 1.847619047619048,
- 0.7380952380952381,
- 0.7380952380952381
- ],
- "vy": [
- 0.5866666666666664,
- 0.5866666666666664,
- 1.7666666666666662,
- 1.7666666666666662,
- 0.5866666666666664
- ]
- },
- "RoiSubsetState": {
- "_type": "glue.core.subset.RoiSubsetState",
- "roi": "PolygonalROI",
- "xatt": "Pixel Axis 1 [x]",
- "yatt": "Pixel Axis 0 [y]"
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "Subset 1": {
- "_type": "glue.core.subset_group.SubsetGroup",
- "label": "Subset 1",
- "state": "RoiSubsetState",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- },
- "subsets": [
- "Subset 1_0",
- "Subset 1_1"
- ]
- },
- "Subset 1_0": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 1",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- }
- },
- "Subset 1_1": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 1",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- }
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "World 0_0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "World 1": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 1"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue.plugins.tools.pv_slicer",
- "glue.viewers.histogram",
- "glue.viewers.table",
- "glue_vispy_viewers.volume",
- "glue.plugins.exporters.plotly",
- "glue.plugins.export_d3po",
- "glue.viewers.image",
- "glue.plugins.tools.spectrum_tool",
- "glue_vispy_viewers.scatter",
- "glue.viewers.scatter",
- "glue.plugins.coordinate_helpers",
- "glue.core.data_exporters"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- [
- "ImageWidget",
- "ImageWidget_0",
- "ImageWidget_1"
- ]
- ]
- },
- "a": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "a"
- },
- "b": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "b"
- },
- "data1": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "data1_0",
- "Component"
- ],
- [
- "Pixel Axis 0 [y]",
- "CoordinateComponent"
- ],
- [
- "Pixel Axis 1 [x]",
- "CoordinateComponent_0"
- ],
- [
- "World 0",
- "CoordinateComponent_1"
- ],
- [
- "World 1",
- "CoordinateComponent_2"
- ],
- [
- "a",
- "DerivedComponent"
- ],
- [
- "b",
- "DerivedComponent_0"
- ]
- ],
- "coords": "Coordinates",
- "label": "data1",
- "primary_owner": [
- "data1_0",
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]",
- "World 0",
- "World 1"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "0.35",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [
- "Subset 1_0"
- ],
- "uuid": "daad10a3-6ad4-4dd4-841a-ca2071dbe467"
- },
- "data1_0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "data1"
- },
- "data2": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "a",
- "Component_0"
- ],
- [
- "Pixel Axis 0 [x]",
- "CoordinateComponent_3"
- ],
- [
- "World 0_0",
- "CoordinateComponent_4"
- ],
- [
- "b",
- "Component_1"
- ],
- [
- "Pixel Axis 1 [x]",
- "DerivedComponent_1"
- ],
- [
- "World 1",
- "DerivedComponent_2"
- ],
- [
- "Pixel Axis 0 [y]",
- "DerivedComponent_3"
- ],
- [
- "World 0",
- "DerivedComponent_4"
- ]
- ],
- "coords": "Coordinates_0",
- "label": "data2",
- "primary_owner": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0_0",
- "b"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 1.0,
- "color": "#e60010",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "^",
- "markersize": 3
- },
- "subsets": [
- "Subset 1_1"
- ],
- "uuid": "e0521c8f-3f02-41b8-8746-a71aa9ae5f49"
- }
-}
diff --git a/glue/viewers/image/qt/tests/data/image_v1.glu b/glue/viewers/image/qt/tests/data/image_v1.glu
deleted file mode 100644
index 0a0b98062..000000000
--- a/glue/viewers/image/qt/tests/data/image_v1.glu
+++ /dev/null
@@ -1,903 +0,0 @@
-{
- "CallbackList": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ImageLayerState",
- "ScatterLayerState",
- "ImageSubsetLayerState"
- ]
- },
- "CallbackList_0": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ImageLayerState_0",
- "ImageSubsetLayerState_0"
- ]
- },
- "CallbackList_1": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ImageLayerState_1",
- "ImageSubsetLayerState_1"
- ]
- },
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDIsIDIpLCB9ICAgICAgICAgIAoBAAAAAAAAAAIAAAAAAAAAAwAAAAAAAAAEAAAAAAAAAA=="
- },
- "units": ""
- },
- "ComponentLink": {
- "_type": "glue.core.component_link.ComponentLink",
- "frm": [
- "a"
- ],
- "hidden": false,
- "inverse": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- },
- "to": [
- "World 0"
- ],
- "using": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- }
- },
- "ComponentLink_0": {
- "_type": "glue.core.component_link.ComponentLink",
- "frm": [
- "World 1"
- ],
- "hidden": false,
- "inverse": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- },
- "to": [
- "b"
- ],
- "using": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- }
- },
- "ComponentLink_1": {
- "_type": "glue.core.component_link.ComponentLink",
- "frm": [
- "World 0"
- ],
- "hidden": false,
- "inverse": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- },
- "to": [
- "a"
- ],
- "using": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- }
- },
- "ComponentLink_2": {
- "_type": "glue.core.component_link.ComponentLink",
- "frm": [
- "b"
- ],
- "hidden": false,
- "inverse": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- },
- "to": [
- "World 1"
- ],
- "using": {
- "_type": "types.FunctionType",
- "function": "glue.core.component_link.identity"
- }
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGY4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDIsKSwgfSAgICAgICAgICAgIAoAAAAAAAD4PwAAAAAAAABA"
- },
- "units": ""
- },
- "Component_1": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGY4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDIsKSwgfSAgICAgICAgICAgIAoAAAAAAADgPwAAAAAAAABA"
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates_0",
- "frm": [
- "World 0_0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]"
- ]
- },
- "CoordinateComponentLink_1": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates_0",
- "frm": [
- "Pixel Axis 0 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0_0"
- ]
- },
- "CoordinateComponentLink_10": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1"
- ],
- "index": 1,
- "pix2world": false,
- "to": [
- "Pixel Axis 1 [x]"
- ]
- },
- "CoordinateComponentLink_2": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]"
- ],
- "index": 1,
- "pix2world": true,
- "to": [
- "World 1"
- ]
- },
- "CoordinateComponentLink_3": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1"
- ],
- "index": 1,
- "pix2world": false,
- "to": [
- "Pixel Axis 1 [x]"
- ]
- },
- "CoordinateComponentLink_4": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates_0",
- "frm": [
- "Pixel Axis 0 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0_0"
- ]
- },
- "CoordinateComponentLink_5": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]"
- ],
- "index": 1,
- "pix2world": true,
- "to": [
- "World 1"
- ]
- },
- "CoordinateComponentLink_6": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates_0",
- "frm": [
- "World 0_0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]"
- ]
- },
- "CoordinateComponentLink_7": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [y]"
- ]
- },
- "CoordinateComponentLink_8": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponentLink_9": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0",
- "World 1"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [y]"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": false
- },
- "CoordinateComponent_1": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "CoordinateComponent_2": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": true
- },
- "CoordinateComponent_3": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponent_4": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "Coordinates_0": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "data1_0",
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]",
- "World 0",
- "World 1",
- "a",
- "b",
- "a",
- "Pixel Axis 0 [x]",
- "World 0_0",
- "b",
- "Pixel Axis 1 [x]",
- "World 1",
- "Pixel Axis 0 [y]",
- "World 0"
- ],
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "CoordinateComponent_1",
- "CoordinateComponent_2",
- "DerivedComponent",
- "DerivedComponent_0",
- "Component_0",
- "CoordinateComponent_3",
- "CoordinateComponent_4",
- "Component_1",
- "DerivedComponent_1",
- "DerivedComponent_2",
- "DerivedComponent_3",
- "DerivedComponent_4"
- ],
- "data": [
- "data1",
- "data2"
- ],
- "groups": [
- "Subset 1"
- ],
- "links": [
- "ComponentLink",
- "ComponentLink_0",
- "CoordinateComponentLink",
- "CoordinateComponentLink_0",
- "ComponentLink_1",
- "CoordinateComponentLink_1",
- "CoordinateComponentLink_2",
- "CoordinateComponentLink_3",
- "CoordinateComponentLink_4",
- "CoordinateComponentLink_5",
- "CoordinateComponentLink_6",
- "CoordinateComponentLink_7",
- "CoordinateComponentLink_8",
- "ComponentLink_2",
- "CoordinateComponentLink_9",
- "CoordinateComponentLink_10"
- ],
- "subset_group_count": 1
- },
- "DerivedComponent": {
- "_type": "glue.core.component.DerivedComponent",
- "link": "ComponentLink_1"
- },
- "DerivedComponent_0": {
- "_type": "glue.core.component.DerivedComponent",
- "link": "ComponentLink_0"
- },
- "DerivedComponent_1": {
- "_type": "glue.core.component.DerivedComponent",
- "link": "CoordinateComponentLink_3"
- },
- "DerivedComponent_2": {
- "_type": "glue.core.component.DerivedComponent",
- "link": "ComponentLink_2"
- },
- "DerivedComponent_3": {
- "_type": "glue.core.component.DerivedComponent",
- "link": "CoordinateComponentLink_7"
- },
- "DerivedComponent_4": {
- "_type": "glue.core.component.DerivedComponent",
- "link": "ComponentLink"
- },
- "ImageLayerState": {
- "_type": "glue.viewers.image.state.ImageLayerState",
- "values": {
- "alpha": 0.8,
- "attribute": "data1_0",
- "bias": 0.5,
- "cmap": "LinearSegmentedColormap",
- "color": "st__0.35",
- "contrast": 1.0,
- "global_sync": true,
- "layer": "data1",
- "percentile": 99,
- "stretch": "st__sqrt",
- "v_max": 3.985,
- "v_min": 1.015,
- "visible": true,
- "zorder": 2
- }
- },
- "ImageLayerState_0": {
- "_type": "glue.viewers.image.state.ImageLayerState",
- "values": {
- "alpha": 0.8,
- "attribute": "data1_0",
- "bias": 0.5,
- "cmap": "LinearSegmentedColormap",
- "color": "st__0.35",
- "contrast": 1.0,
- "global_sync": true,
- "layer": "data1",
- "percentile": "st__Custom",
- "stretch": "st__arcsinh",
- "v_max": 4,
- "v_min": 1,
- "visible": true,
- "zorder": 2
- }
- },
- "ImageLayerState_1": {
- "_type": "glue.viewers.image.state.ImageLayerState",
- "values": {
- "alpha": 0.8,
- "attribute": "data1_0",
- "bias": 0.5,
- "cmap": "LinearSegmentedColormap",
- "color": "st__0.35",
- "contrast": 1.0,
- "global_sync": true,
- "layer": "data1",
- "percentile": "st__Custom",
- "stretch": "st__linear",
- "v_max": 2.0,
- "v_min": -2.0,
- "visible": true,
- "zorder": 2
- }
- },
- "ImageSubsetLayerState": {
- "_type": "glue.viewers.image.state.ImageSubsetLayerState",
- "values": {
- "alpha": 0.5,
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "visible": false,
- "zorder": 4
- }
- },
- "ImageSubsetLayerState_0": {
- "_type": "glue.viewers.image.state.ImageSubsetLayerState",
- "values": {
- "alpha": 0.5,
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "visible": true,
- "zorder": 3
- }
- },
- "ImageSubsetLayerState_1": {
- "_type": "glue.viewers.image.state.ImageSubsetLayerState",
- "values": {
- "alpha": 0.5,
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "visible": true,
- "zorder": 3
- }
- },
- "ImageViewer": {
- "_protocol": 1,
- "_type": "glue.viewers.image.qt.data_viewer.ImageViewer",
- "layers": [
- {
- "_type": "glue.viewers.image.layer_artist.ImageLayerArtist",
- "state": "ImageLayerState"
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "state": "ScatterLayerState"
- },
- {
- "_type": "glue.viewers.image.layer_artist.ImageSubsetLayerArtist",
- "state": "ImageSubsetLayerState"
- }
- ],
- "pos": [
- -1,
- 1
- ],
- "session": "Session",
- "size": [
- 568,
- 490
- ],
- "state": {
- "values": {
- "aspect": "st__equal",
- "color_mode": "st__Colormaps",
- "layers": "CallbackList",
- "reference_data": "data1",
- "slices": [
- 0,
- 0
- ],
- "x_att": "Pixel Axis 1 [x]",
- "x_att_world": "World 1",
- "x_log": false,
- "x_max": 1.937,
- "x_min": -0.936,
- "y_att": "Pixel Axis 0 [y]",
- "y_att_world": "World 0",
- "y_log": false,
- "y_max": 1.5,
- "y_min": -0.5
- }
- }
- },
- "ImageViewer_0": {
- "_protocol": 1,
- "_type": "glue.viewers.image.qt.data_viewer.ImageViewer",
- "layers": [
- {
- "_type": "glue.viewers.image.layer_artist.ImageLayerArtist",
- "state": "ImageLayerState_0"
- },
- {
- "_type": "glue.viewers.image.layer_artist.ImageSubsetLayerArtist",
- "state": "ImageSubsetLayerState_0"
- }
- ],
- "pos": [
- 568,
- 1
- ],
- "session": "Session",
- "size": [
- 606,
- 489
- ],
- "state": {
- "values": {
- "aspect": "st__equal",
- "color_mode": "st__Colormaps",
- "layers": "CallbackList_0",
- "reference_data": "data1",
- "slices": [
- 0,
- 0
- ],
- "x_att": "Pixel Axis 1 [x]",
- "x_att_world": "World 1",
- "x_log": false,
- "x_max": 1.937,
- "x_min": -0.936,
- "y_att": "Pixel Axis 0 [y]",
- "y_att_world": "World 0",
- "y_log": false,
- "y_max": 1.5,
- "y_min": -0.5
- }
- }
- },
- "ImageViewer_1": {
- "_protocol": 1,
- "_type": "glue.viewers.image.qt.data_viewer.ImageViewer",
- "layers": [
- {
- "_type": "glue.viewers.image.layer_artist.ImageLayerArtist",
- "state": "ImageLayerState_1"
- },
- {
- "_type": "glue.viewers.image.layer_artist.ImageSubsetLayerArtist",
- "state": "ImageSubsetLayerState_1"
- }
- ],
- "pos": [
- 569,
- 488
- ],
- "session": "Session",
- "size": [
- 600,
- 400
- ],
- "state": {
- "values": {
- "aspect": "st__equal",
- "color_mode": "st__Colormaps",
- "layers": "CallbackList_1",
- "reference_data": "data1",
- "slices": [
- 0,
- 0
- ],
- "x_att": "Pixel Axis 1 [x]",
- "x_att_world": "World 1",
- "x_log": false,
- "x_max": 1.937,
- "x_min": -0.936,
- "y_att": "Pixel Axis 0 [y]",
- "y_att_world": "World 0",
- "y_log": false,
- "y_max": 1.5,
- "y_min": -0.5
- }
- }
- },
- "LinearSegmentedColormap": {
- "_type": "matplotlib.colors.LinearSegmentedColormap",
- "cmap": "gray"
- },
- "Pixel Axis 0 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [x]"
- },
- "Pixel Axis 0 [y]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [y]"
- },
- "Pixel Axis 1 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 1,
- "hidden": true,
- "label": "Pixel Axis 1 [x]"
- },
- "PolygonalROI": {
- "_type": "glue.core.roi.PolygonalROI",
- "vx": [
- 0.7380952380952381,
- 1.847619047619048,
- 1.847619047619048,
- 0.7380952380952381,
- 0.7380952380952381
- ],
- "vy": [
- 0.5866666666666664,
- 0.5866666666666664,
- 1.7666666666666662,
- 1.7666666666666662,
- 0.5866666666666664
- ]
- },
- "RoiSubsetState": {
- "_type": "glue.core.subset.RoiSubsetState",
- "roi": "PolygonalROI",
- "xatt": "Pixel Axis 1 [x]",
- "yatt": "Pixel Axis 0 [y]"
- },
- "ScatterLayerState": {
- "_type": "glue.viewers.scatter.state.ScatterLayerState",
- "values": {
- "alpha": 1.0,
- "color": "st__#e60010",
- "layer": "data2",
- "size": 3,
- "visible": true,
- "zorder": 3
- }
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "Subset 1": {
- "_type": "glue.core.subset_group.SubsetGroup",
- "label": "Subset 1",
- "state": "RoiSubsetState",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- },
- "subsets": [
- "Subset 1_0",
- "Subset 1_1"
- ]
- },
- "Subset 1_0": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 1",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- }
- },
- "Subset 1_1": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 1",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- }
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "World 0_0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "World 1": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 1"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue.viewers.image",
- "glue.plugins.exporters.plotly",
- "specviz.app",
- "glue.viewers.scatter",
- "glue.viewers.histogram",
- "glue.core.data_exporters",
- "glue.plugins.tools.spectrum_tool",
- "glue.viewers.table",
- "glue_medical",
- "glue_vispy_viewers.scatter",
- "glue_vispy_viewers.volume",
- "glue.plugins.coordinate_helpers",
- "glue.plugins.tools.pv_slicer",
- "glue.plugins.export_d3po"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- [
- "ImageViewer",
- "ImageViewer_0",
- "ImageViewer_1"
- ]
- ]
- },
- "a": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "a"
- },
- "b": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "b"
- },
- "data1": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "data1_0",
- "Component"
- ],
- [
- "Pixel Axis 0 [y]",
- "CoordinateComponent"
- ],
- [
- "Pixel Axis 1 [x]",
- "CoordinateComponent_0"
- ],
- [
- "World 0",
- "CoordinateComponent_1"
- ],
- [
- "World 1",
- "CoordinateComponent_2"
- ],
- [
- "a",
- "DerivedComponent"
- ],
- [
- "b",
- "DerivedComponent_0"
- ]
- ],
- "coords": "Coordinates",
- "label": "data1",
- "primary_owner": [
- "data1_0",
- "Pixel Axis 0 [y]",
- "Pixel Axis 1 [x]",
- "World 0",
- "World 1"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "0.35",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [
- "Subset 1_0"
- ],
- "uuid": "daad10a3-6ad4-4dd4-841a-ca2071dbe467"
- },
- "data1_0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "data1"
- },
- "data2": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "a",
- "Component_0"
- ],
- [
- "Pixel Axis 0 [x]",
- "CoordinateComponent_3"
- ],
- [
- "World 0_0",
- "CoordinateComponent_4"
- ],
- [
- "b",
- "Component_1"
- ],
- [
- "Pixel Axis 1 [x]",
- "DerivedComponent_1"
- ],
- [
- "World 1",
- "DerivedComponent_2"
- ],
- [
- "Pixel Axis 0 [y]",
- "DerivedComponent_3"
- ],
- [
- "World 0",
- "DerivedComponent_4"
- ]
- ],
- "coords": "Coordinates_0",
- "label": "data2",
- "primary_owner": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0_0",
- "b"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 1.0,
- "color": "#e60010",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "^",
- "markersize": 3
- },
- "subsets": [
- "Subset 1_1"
- ],
- "uuid": "e0521c8f-3f02-41b8-8746-a71aa9ae5f49"
- }
-}
diff --git a/glue/viewers/image/qt/tests/test_data_viewer.py b/glue/viewers/image/qt/tests/test_data_viewer.py
deleted file mode 100644
index c4a5031c7..000000000
--- a/glue/viewers/image/qt/tests/test_data_viewer.py
+++ /dev/null
@@ -1,973 +0,0 @@
-# pylint: disable=I0011,W0613,W0201,W0212,E1101,E1103
-
-import os
-import gc
-from collections import Counter
-
-import pytest
-
-from astropy.wcs import WCS
-
-import numpy as np
-from numpy.testing import assert_allclose
-
-from glue.viewers.image.frb_artist import FRBArtist
-from glue.core.coordinates import IdentityCoordinates
-from glue.core.message import SubsetUpdateMessage
-from glue.core import HubListener, Data
-from glue.core.roi import XRangeROI, RectangularROI
-from glue.core.subset import RoiSubsetState
-from glue.utils.qt import combo_as_string, process_events
-from glue.viewers.matplotlib.qt.tests.test_data_viewer import BaseTestMatplotlibDataViewer
-from glue.core.state import GlueUnSerializer
-from glue.app.qt.layer_tree_widget import LayerTreeWidget
-from glue.viewers.scatter.state import ScatterLayerState
-from glue.viewers.image.state import ImageLayerState, ImageSubsetLayerState, AggregateSlice
-from glue.core.link_helpers import LinkSame
-from glue.app.qt import GlueApplication
-from glue.core.fixed_resolution_buffer import ARRAY_CACHE, PIXEL_CACHE
-from glue.core.data_derived import IndexedData
-
-from ..data_viewer import ImageViewer
-
-DATA = os.path.join(os.path.dirname(__file__), 'data')
-
-
-class TestImageCommon(BaseTestMatplotlibDataViewer):
-
- def init_data(self):
- return Data(label='d1', x=np.arange(24).reshape((2, 3, 4)), y=np.ones((2, 3, 4)))
-
- viewer_cls = ImageViewer
-
- @pytest.mark.skip()
- def test_double_add_ignored(self):
- pass
-
- def test_update_data_processed_if_data_present(self):
-
- # Patch for the main test of the same name - we need to explicilty set
- # global_sync to True here for things to work correctly.
-
- self.init_draw_count()
- self.data_collection.append(self.data)
- self.viewer.add_data(self.data)
- ct0 = self.draw_count
- self.viewer.state.layers[0].global_sync = True
- self.data.style.color = 'blue'
- assert self.draw_count > ct0
-
- def test_slice_change_single_draw(self):
-
- # Regression test for a bug that caused Matplotlib to draw once per
- # data/subset when changing slices.
-
- self.viewer.add_data(self.data)
-
- self.data_collection.new_subset_group(label='a', subset_state=self.data.id['x'] > 1)
- self.data_collection.new_subset_group(label='b', subset_state=self.data.id['x'] > 2)
- self.data_collection.new_subset_group(label='c', subset_state=self.data.id['x'] > 3)
-
- self.init_draw_count()
-
- assert self.draw_count == 0
- self.viewer.state.slices = (1, 1, 1)
- assert self.draw_count == 1
-
-
-class MyCoords(IdentityCoordinates):
-
- def __init__(self, n_dim=2):
- super().__init__(n_dim=n_dim)
-
- @property
- def world_axis_names(self):
- return ['Apple', 'Banana']
-
-
-class TestImageViewer(object):
-
- def setup_method(self, method):
-
- self.coords = MyCoords()
- self.image1 = Data(label='image1', x=[[1, 2], [3, 4]], y=[[4, 5], [2, 3]])
- self.image2 = Data(label='image2', a=[[3, 3], [2, 2]], b=[[4, 4], [3, 2]],
- coords=self.coords)
- self.catalog = Data(label='catalog', c=[1, 3, 2], d=[4, 3, 3])
- self.hypercube = Data(label='hypercube', x=np.arange(120).reshape((2, 3, 4, 5)))
-
- # Create data versions with WCS coordinates
- self.image1_wcs = Data(label='image1_wcs', x=self.image1['x'],
- coords=WCS(naxis=2))
- self.hypercube_wcs = Data(label='hypercube_wcs', x=self.hypercube['x'],
- coords=WCS(naxis=4))
-
- self.application = GlueApplication()
-
- self.session = self.application.session
-
- self.hub = self.session.hub
-
- self.data_collection = self.session.data_collection
- self.data_collection.append(self.image1)
- self.data_collection.append(self.image2)
- self.data_collection.append(self.catalog)
- self.data_collection.append(self.hypercube)
- self.data_collection.append(self.image1_wcs)
- self.data_collection.append(self.hypercube_wcs)
-
- self.viewer = self.application.new_data_viewer(ImageViewer)
-
- self.data_collection.register_to_hub(self.hub)
- self.viewer.register_to_hub(self.hub)
-
- self.options_widget = self.viewer.options_widget()
-
- def teardown_method(self, method):
-
- # Properly close viewer and application
- self.viewer.close()
- self.viewer = None
- self.application.close()
- self.application = None
-
- # Make sure cache is empty
- if len(PIXEL_CACHE) > 0:
- raise Exception("Pixel cache contains {0} elements".format(len(PIXEL_CACHE)))
- if len(ARRAY_CACHE) > 0:
- raise Exception("Array cache contains {0} elements".format(len(ARRAY_CACHE)))
-
- def test_basic(self):
-
- # Check defaults when we add data
-
- self.viewer.add_data(self.image1)
-
- assert combo_as_string(self.options_widget.ui.combosel_x_att_world) == 'Coordinate components:Pixel Axis 0 [y]:Pixel Axis 1 [x]'
- assert combo_as_string(self.options_widget.ui.combosel_y_att_world) == 'Coordinate components:Pixel Axis 0 [y]:Pixel Axis 1 [x]'
-
- assert self.viewer.axes.get_xlabel() == 'Pixel Axis 1 [x]'
- assert self.viewer.state.x_att_world is self.image1.id['Pixel Axis 1 [x]']
- assert self.viewer.state.x_att is self.image1.pixel_component_ids[1]
- assert_allclose(self.viewer.state.x_min, -0.8419913419913423)
- assert_allclose(self.viewer.state.x_max, +1.8419913419913423)
-
- assert self.viewer.axes.get_ylabel() == 'Pixel Axis 0 [y]'
- assert self.viewer.state.y_att_world is self.image1.id['Pixel Axis 0 [y]']
- assert self.viewer.state.y_att is self.image1.pixel_component_ids[0]
- assert self.viewer.state.y_min == -0.5
- assert self.viewer.state.y_max == +1.5
-
- assert not self.viewer.state.x_log
- assert not self.viewer.state.y_log
-
- assert len(self.viewer.state.layers) == 1
-
- def test_custom_coords(self):
-
- # Check defaults when we add data with coordinates
-
- self.viewer.add_data(self.image2)
-
- assert combo_as_string(self.options_widget.ui.combosel_x_att_world) == 'Coordinate components:Banana:Apple'
- assert combo_as_string(self.options_widget.ui.combosel_x_att_world) == 'Coordinate components:Banana:Apple'
-
- assert self.viewer.axes.get_xlabel() == 'Apple'
- assert self.viewer.state.x_att_world is self.image2.id['Apple']
- assert self.viewer.state.x_att is self.image2.pixel_component_ids[1]
- assert self.viewer.axes.get_ylabel() == 'Banana'
- assert self.viewer.state.y_att_world is self.image2.id['Banana']
- assert self.viewer.state.y_att is self.image2.pixel_component_ids[0]
-
- def test_flip(self):
-
- self.viewer.add_data(self.image1)
-
- x_min_start = self.viewer.state.x_min
- x_max_start = self.viewer.state.x_max
-
- self.options_widget.button_flip_x.click()
-
- assert self.viewer.state.x_min == x_max_start
- assert self.viewer.state.x_max == x_min_start
-
- y_min_start = self.viewer.state.y_min
- y_max_start = self.viewer.state.y_max
-
- self.options_widget.button_flip_y.click()
-
- assert self.viewer.state.y_min == y_max_start
- assert self.viewer.state.y_max == y_min_start
-
- def test_combo_updates_with_component_add(self):
- self.viewer.add_data(self.image1)
- self.image1.add_component([[9, 9], [8, 8]], 'z')
- assert self.viewer.state.x_att_world is self.image1.id['Pixel Axis 1 [x]']
- assert self.viewer.state.y_att_world is self.image1.id['Pixel Axis 0 [y]']
- # TODO: there should be an easier way to do this
- layer_style_editor = self.viewer._view.layout_style_widgets[self.viewer.layers[0]]
- assert combo_as_string(layer_style_editor.ui.combosel_attribute) == 'x:y:z'
-
- def test_apply_roi(self):
-
- self.viewer.add_data(self.image1)
-
- roi = RectangularROI(0.4, 1.6, -0.6, 0.6)
-
- assert len(self.viewer.layers) == 1
-
- self.viewer.apply_roi(roi)
-
- assert len(self.viewer.layers) == 2
- assert len(self.image1.subsets) == 1
-
- assert_allclose(self.image1.subsets[0].to_mask(), [[0, 1], [0, 0]])
-
- state = self.image1.subsets[0].subset_state
- assert isinstance(state, RoiSubsetState)
-
- def test_apply_roi_empty(self):
- # Make sure that doing an ROI selection on an empty viewer doesn't
- # produce error messsages
- roi = XRangeROI(-0.2, 0.1)
- self.viewer.apply_roi(roi)
-
- def test_identical(self):
-
- # Check what happens if we set both attributes to the same coordinates
-
- self.viewer.add_data(self.image2)
-
- assert self.viewer.state.x_att_world is self.image2.id['Apple']
- assert self.viewer.state.y_att_world is self.image2.id['Banana']
-
- self.viewer.state.y_att_world = self.image2.id['Apple']
-
- assert self.viewer.state.x_att_world is self.image2.id['Banana']
- assert self.viewer.state.y_att_world is self.image2.id['Apple']
-
- self.viewer.state.x_att_world = self.image2.id['Apple']
-
- assert self.viewer.state.x_att_world is self.image2.id['Apple']
- assert self.viewer.state.y_att_world is self.image2.id['Banana']
-
- def test_duplicate_subsets(self):
-
- # Regression test: make sure that when adding a seconda layer for the
- # same dataset, we don't add the subsets all over again.
-
- self.viewer.add_data(self.image1)
- self.data_collection.new_subset_group(subset_state=self.image1.id['x'] > 1, label='A')
-
- assert len(self.viewer.layers) == 2
-
- self.viewer.add_data(self.image1)
-
- assert len(self.viewer.layers) == 3
-
- def test_aspect_subset(self):
-
- self.viewer.add_data(self.image1)
-
- assert self.viewer.state.aspect == 'equal'
-
- self.viewer.state.aspect = 'auto'
-
- self.data_collection.new_subset_group('s1', self.image1.id['x'] > 0.)
-
- assert len(self.viewer.state.layers) == 2
-
- assert self.viewer.state.aspect == 'auto'
-
- self.viewer.state.aspect = 'equal'
-
- self.data_collection.new_subset_group('s2', self.image1.id['x'] > 1.)
-
- assert len(self.viewer.state.layers) == 3
-
- assert self.viewer.state.aspect == 'equal'
-
- def test_hypercube(self):
-
- # Check defaults when we add data
-
- self.viewer.add_data(self.hypercube)
-
- assert combo_as_string(self.options_widget.ui.combosel_x_att_world) == 'Coordinate components:Pixel Axis 0:Pixel Axis 1:Pixel Axis 2:Pixel Axis 3'
- assert combo_as_string(self.options_widget.ui.combosel_x_att_world) == 'Coordinate components:Pixel Axis 0:Pixel Axis 1:Pixel Axis 2:Pixel Axis 3'
-
- assert self.viewer.axes.get_xlabel() == 'Pixel Axis 3'
- assert self.viewer.state.x_att_world is self.hypercube.id['Pixel Axis 3']
- assert self.viewer.state.x_att is self.hypercube.pixel_component_ids[3]
- assert_allclose(self.viewer.state.x_min, -0.6839826839826846)
- assert_allclose(self.viewer.state.x_max, +4.6839826839826846)
-
- assert self.viewer.axes.get_ylabel() == 'Pixel Axis 2'
- assert self.viewer.state.y_att_world is self.hypercube.id['Pixel Axis 2']
- assert self.viewer.state.y_att is self.hypercube.pixel_component_ids[2]
- assert self.viewer.state.y_min == -0.5
- assert self.viewer.state.y_max == +3.5
-
- assert not self.viewer.state.x_log
- assert not self.viewer.state.y_log
-
- assert len(self.viewer.state.layers) == 1
-
- def test_hypercube_world(self):
-
- # Check defaults when we add data
-
- wcs = WCS(naxis=4)
- hypercube2 = Data()
- hypercube2.coords = wcs
- hypercube2.add_component(np.random.random((2, 3, 4, 5)), 'a')
-
- self.data_collection.append(hypercube2)
-
- self.viewer.add_data(hypercube2)
-
- def test_incompatible_subset(self):
- self.viewer.add_data(self.image1)
- self.data_collection.new_subset_group(subset_state=self.catalog.id['c'] > 1, label='A')
-
- def test_invisible_subset(self):
-
- # Regression test for a bug that caused a subset layer that started
- # off as invisible to have issues when made visible. We emulate the
- # initial invisible (but enabled) state by invalidating the cache.
-
- self.viewer.add_data(self.image1)
- self.data_collection.new_subset_group(subset_state=self.image1.id['x'] > 1, label='A')
- self.viewer.layers[1].visible = False
- self.viewer.layers[1].image_artist.invalidate_cache()
- self.viewer.layers[1].redraw()
- process_events()
- assert not np.any(self.viewer.layers[1].image_artist._A.mask)
- self.viewer.layers[1].visible = True
- assert not np.any(self.viewer.layers[1].image_artist._A.mask)
-
- def test_apply_roi_single(self):
-
- # Regression test for a bug that caused mode.update to be called
- # multiple times and resulted in all other viewers receiving many
- # messages regarding subset updates (this occurred when multiple)
- # datasets were present.
-
- layer_tree = LayerTreeWidget(session=self.session)
- layer_tree.set_checkable(False)
- layer_tree.setup(self.data_collection)
- layer_tree.bind_selection_to_edit_subset()
-
- class Client(HubListener):
-
- def __init__(self, *args, **kwargs):
- super(Client, self).__init__(*args, **kwargs)
- self.count = Counter()
-
- def ping(self, message):
- self.count[message.sender] += 1
-
- def register_to_hub(self, hub):
- hub.subscribe(self, SubsetUpdateMessage, handler=self.ping)
-
- d1 = Data(a=[[1, 2], [3, 4]], label='d1')
- d2 = Data(b=[[1, 2], [3, 4]], label='d2')
- d3 = Data(c=[[1, 2], [3, 4]], label='d3')
- d4 = Data(d=[[1, 2], [3, 4]], label='d4')
-
- self.data_collection.append(d1)
- self.data_collection.append(d2)
- self.data_collection.append(d3)
- self.data_collection.append(d4)
-
- client = Client()
- client.register_to_hub(self.hub)
-
- self.viewer.add_data(d1)
- self.viewer.add_data(d3)
-
- roi = XRangeROI(2.5, 3.5)
- self.viewer.apply_roi(roi)
-
- for subset in client.count:
- assert client.count[subset] == 1
-
- def test_disable_incompatible(self):
-
- # Test to make sure that image and image subset layers are disabled if
- # their pixel coordinates are not compatible with the ones of the
- # reference data.
-
- self.viewer.add_data(self.image1)
- self.viewer.add_data(self.image2)
-
- assert self.viewer.state.reference_data is self.image1
-
- self.data_collection.new_subset_group()
-
- process_events()
-
- assert len(self.viewer.layers) == 4
-
- # Only the two layers associated with the reference data should be enabled
- for layer_artist in self.viewer.layers:
- if layer_artist.layer in (self.image1, self.image1.subsets[0]):
- assert layer_artist.enabled
- else:
- assert not layer_artist.enabled
-
- py1, px1 = self.image1.pixel_component_ids
- py2, px2 = self.image2.pixel_component_ids
-
- link1 = LinkSame(px1, px2)
- self.data_collection.add_link(link1)
-
- process_events()
-
- # One link isn't enough, second dataset layers are still not enabled
-
- for layer_artist in self.viewer.layers:
- if layer_artist.layer in (self.image1, self.image1.subsets[0]):
- assert layer_artist.enabled
- else:
- assert not layer_artist.enabled
-
- link2 = LinkSame(py1, py2)
- self.data_collection.add_link(link2)
-
- process_events()
-
- # All layers should now be enabled
-
- for layer_artist in self.viewer.layers:
- assert layer_artist.enabled
-
- self.data_collection.remove_link(link2)
-
- process_events()
-
- # We should now be back to the original situation
-
- for layer_artist in self.viewer.layers:
- if layer_artist.layer in (self.image1, self.image1.subsets[0]):
- assert layer_artist.enabled
- else:
- assert not layer_artist.enabled
-
- def test_change_reference_data(self, capsys):
-
- # Test to make sure everything works fine if we change the reference data.
-
- self.viewer.add_data(self.image1)
- self.viewer.add_data(self.image2)
-
- assert self.viewer.state.reference_data is self.image1
- assert self.viewer.state.x_att_world is self.image1.pixel_component_ids[-1]
- assert self.viewer.state.y_att_world is self.image1.pixel_component_ids[-2]
- assert self.viewer.state.x_att is self.image1.pixel_component_ids[-1]
- assert self.viewer.state.y_att is self.image1.pixel_component_ids[-2]
-
- self.viewer.state.reference_data = self.image2
-
- assert self.viewer.state.reference_data is self.image2
- assert self.viewer.state.x_att_world is self.image2.world_component_ids[-1]
- assert self.viewer.state.y_att_world is self.image2.world_component_ids[-2]
- assert self.viewer.state.x_att is self.image2.pixel_component_ids[-1]
- assert self.viewer.state.y_att is self.image2.pixel_component_ids[-2]
-
- self.viewer.state.reference_data = self.image1
-
- assert self.viewer.state.reference_data is self.image1
- assert self.viewer.state.x_att_world is self.image1.pixel_component_ids[-1]
- assert self.viewer.state.y_att_world is self.image1.pixel_component_ids[-2]
- assert self.viewer.state.x_att is self.image1.pixel_component_ids[-1]
- assert self.viewer.state.y_att is self.image1.pixel_component_ids[-2]
-
- # Some exceptions used to happen during callbacks, and these show up
- # in stderr but don't interrupt the code, so we make sure here that
- # nothing was printed to stdout nor stderr.
-
- out, err = capsys.readouterr()
-
- assert out.strip() == ""
- assert err.strip() == ""
-
- @pytest.mark.parametrize('wcs', [False, True])
- def test_change_reference_data_dimensionality(self, capsys, wcs):
-
- # Regression test for a bug that caused an exception when changing
- # the dimensionality of the reference data
-
- if wcs:
- first = self.image1_wcs
- second = self.hypercube_wcs
- else:
- first = self.image1
- second = self.hypercube
-
- self.viewer.add_data(first)
- self.viewer.add_data(second)
-
- assert self.viewer.state.reference_data is first
- if wcs:
- assert self.viewer.state.x_att_world is first.world_component_ids[-1]
- assert self.viewer.state.y_att_world is first.world_component_ids[-2]
- else:
- assert self.viewer.state.x_att_world is first.pixel_component_ids[-1]
- assert self.viewer.state.y_att_world is first.pixel_component_ids[-2]
- assert self.viewer.state.x_att is first.pixel_component_ids[-1]
- assert self.viewer.state.y_att is first.pixel_component_ids[-2]
-
- self.viewer.state.reference_data = second
-
- assert self.viewer.state.reference_data is second
- if wcs:
- assert self.viewer.state.x_att_world is second.world_component_ids[-1]
- assert self.viewer.state.y_att_world is second.world_component_ids[-2]
- else:
- assert self.viewer.state.x_att_world is second.pixel_component_ids[-1]
- assert self.viewer.state.y_att_world is second.pixel_component_ids[-2]
- assert self.viewer.state.x_att is second.pixel_component_ids[-1]
- assert self.viewer.state.y_att is second.pixel_component_ids[-2]
-
- self.viewer.state.reference_data = first
-
- assert self.viewer.state.reference_data is first
- if wcs:
- assert self.viewer.state.x_att_world is first.world_component_ids[-1]
- assert self.viewer.state.y_att_world is first.world_component_ids[-2]
- else:
- assert self.viewer.state.x_att_world is first.pixel_component_ids[-1]
- assert self.viewer.state.y_att_world is first.pixel_component_ids[-2]
- assert self.viewer.state.x_att is first.pixel_component_ids[-1]
- assert self.viewer.state.y_att is first.pixel_component_ids[-2]
-
- # Some exceptions used to happen during callbacks, and these show up
- # in stderr but don't interrupt the code, so we make sure here that
- # nothing was printed to stdout nor stderr.
-
- out, err = capsys.readouterr()
-
- assert out.strip() == ""
- assert err.strip() == ""
-
- def test_scatter_overlay(self):
- self.viewer.add_data(self.image1)
- self.viewer.add_data(self.catalog)
-
- def test_removed_subset(self):
-
- # Regression test for a bug in v0.11.0 that meant that if a subset
- # was removed, the image viewer would then crash when changing view
- # (e.g. zooming in). The bug was caused by undeleted references to
- # FRBArtist due to circular references. We therefore check in this
- # test how many FRBArtist objects exist.
-
- def get_frb_artists():
- mi = []
- gc.collect()
- for obj in gc.get_objects():
- try:
- if isinstance(obj, FRBArtist):
- mi.append(obj)
- except ReferenceError:
- pass
- return mi
-
- # The viewer starts off with one FRBArtist. This is also a good test
- # that other FRBArtist in other tests have been removed.
- assert len(get_frb_artists()) == 1
-
- large_image = Data(x=np.random.random((2048, 2048)))
- self.data_collection.append(large_image)
-
- # The subset group can be made from any dataset
- subset_group = self.data_collection.new_subset_group(subset_state=self.image1.id['x'] > 1, label='A')
-
- self.viewer.add_data(large_image)
-
- # Since the dataset added has a subset, and each subset has its own
- # FRBArtist, this increases the count.
- assert len(get_frb_artists()) == 2
-
- assert len(self.viewer.layers) == 2
-
- self.data_collection.remove_subset_group(subset_group)
-
- # Removing the subset should bring the count back to 1 again
- assert len(get_frb_artists()) == 1
-
- def test_select_previously_incompatible_layer(self):
-
- # Regression test for a bug that caused a selection in a previously disabled
- # layer to enable the layer without updating the subset view
-
- self.viewer.add_data(self.image1)
- self.viewer.add_data(self.catalog)
- self.catalog.add_component([4, 5, 6], 'e')
-
- link1 = LinkSame(self.catalog.id['c'], self.image1.pixel_component_ids[0])
- link2 = LinkSame(self.catalog.id['d'], self.image1.pixel_component_ids[1])
- self.data_collection.add_link(link1)
- self.data_collection.add_link(link2)
-
- self.data_collection.new_subset_group(subset_state=self.catalog.id['e'] > 4)
-
- process_events()
-
- assert self.viewer.layers[0].enabled # image
- assert self.viewer.layers[1].enabled # scatter
- assert not self.viewer.layers[2].enabled # image subset
- assert self.viewer.layers[3].enabled # scatter subset
-
- assert not self.viewer.layers[2].image_artist.get_visible()
-
- self.data_collection.subset_groups[0].subset_state = self.catalog.id['c'] > -1
-
- process_events()
-
- assert self.viewer.layers[0].enabled # image
- assert self.viewer.layers[1].enabled # scatter
- assert self.viewer.layers[2].enabled # image subset
- assert self.viewer.layers[3].enabled # scatter subset
-
- assert self.viewer.layers[2].image_artist.get_visible()
-
- def test_linking_and_enabling(self):
-
- # Regression test for a bug that caused layers not not be correctly
- # enabled/disabled.
-
- self.viewer.add_data(self.image1)
- self.viewer.add_data(self.catalog)
- self.catalog.add_component([4, 5, 6], 'e')
-
- self.data_collection.new_subset_group(subset_state=self.catalog.id['e'] > 4)
-
- process_events()
-
- assert self.viewer.layers[0].enabled # image
- assert not self.viewer.layers[1].enabled # scatter
- assert not self.viewer.layers[2].enabled # image subset
- assert not self.viewer.layers[3].enabled # scatter subset
-
- link1 = LinkSame(self.catalog.id['c'], self.image1.pixel_component_ids[0])
- link2 = LinkSame(self.catalog.id['d'], self.image1.pixel_component_ids[1])
- self.data_collection.add_link(link1)
- self.data_collection.add_link(link2)
-
- process_events()
-
- assert self.viewer.layers[0].enabled # image
- assert self.viewer.layers[1].enabled # scatter
- assert not self.viewer.layers[2].enabled # image subset
- assert self.viewer.layers[3].enabled # scatter subset
-
- def test_save_aggregate_slice(self, tmpdir):
-
- # Regression test to make sure that image viewers that include
- # aggregate slice objects in the slices can be saved/restored
-
- self.viewer.add_data(self.hypercube)
- self.viewer.state.slices = AggregateSlice(slice(1, 3), 10, np.sum), 3, 0, 0
-
- filename = tmpdir.join('session.glu').strpath
-
- self.application.save_session(filename)
- self.application.close()
-
- app2 = GlueApplication.restore_session(filename)
- viewer_state = app2.viewers[0][0].state
- slices = viewer_state.slices
- assert isinstance(slices[0], AggregateSlice)
- assert slices[0].slice == slice(1, 3)
- assert slices[0].center == 10
- assert slices[0].function is np.sum
- assert slices[1:] == (3, 0, 0)
-
- app2.close()
-
- def test_subset_cube_image(self):
-
- # Regression test to make sure that if an image and cube are present
- # in an image viewer and a subset is also present, we don't get an
- # error when trying to access the subset shape
-
- self.viewer.add_data(self.image1)
- self.data_collection.new_subset_group(label='subset',
- subset_state=self.image1.id['x'] > 1.5)
-
- self.viewer.add_data(self.hypercube)
- self.viewer.state.reference_data = self.hypercube
-
- assert self.viewer.layers[1].subset_array.shape == (4, 5)
- assert self.viewer.layers[3].subset_array.shape == (4, 5)
-
- def test_preserve_slice(self):
-
- # Regression test to make sure that when adding a second dataset to
- # an image viewer, the current slice in a cube does not change.
-
- self.viewer.add_data(self.hypercube)
- self.viewer.state.slices = (1, 2, 3, 4)
- self.viewer.add_data(self.image1)
- assert self.viewer.state.slices == (1, 2, 3, 4)
-
- def test_close(self):
-
- # Regression test for a bug that caused an error related to the toolbar
- # and _mpl_nav not being present when closing the viewer.
-
- self.viewer.toolbar.active_tool = self.viewer.toolbar.tools['mpl:zoom']
- self.viewer.close(warn=False)
-
- def test_legend(self):
- from matplotlib.colors import to_hex
-
- viewer_state = self.viewer.state
- self.viewer.add_data(self.image1)
- self.viewer.state.legend.visible = True
-
- handles, labels, handler_dict = self.viewer.get_handles_legend()
- assert len(handles) == 1
- assert labels[0] == 'image1'
-
- self.data_collection.new_subset_group('test', self.image1.id['x'] > 1)
- assert len(viewer_state.layers) == 2
- handles, labels, handler_dict = self.viewer.get_handles_legend()
- assert len(handles) == 2
- assert labels[1] == 'test'
-
- assert to_hex(handles[1].get_facecolor()) == viewer_state.layers[1].color
-
- def test_limit_resetting(self):
-
- # Test to make sure that the limits only change if the reference data
- # is changed
-
- self.viewer.state.aspect = 'auto'
-
- self.viewer.add_data(self.image1)
-
- self.viewer.state.x_min = 0.2
- self.viewer.state.x_max = 0.4
- self.viewer.state.y_min = 0.3
- self.viewer.state.y_max = 0.5
-
- self.viewer.add_data(self.image2)
-
- assert self.viewer.state.x_min == 0.2
- assert self.viewer.state.x_max == 0.4
- assert self.viewer.state.y_min == 0.3
- assert self.viewer.state.y_max == 0.5
-
- self.viewer.state.reference_data = self.image2
-
- assert self.viewer.state.x_min == -0.5
- assert self.viewer.state.x_max == 1.5
- assert self.viewer.state.y_min == -0.5
- assert self.viewer.state.y_max == 1.5
-
-
-class TestSessions(object):
-
- @pytest.mark.parametrize('protocol', [0, 1])
- def test_session_back_compat(self, protocol):
-
- filename = os.path.join(DATA, 'image_v{0}.glu'.format(protocol))
-
- with open(filename, 'r') as f:
- session = f.read()
-
- state = GlueUnSerializer.loads(session)
-
- ga = state.object('__main__')
-
- dc = ga.session.data_collection
-
- assert len(dc) == 2
-
- assert dc[0].label == 'data1'
- assert dc[1].label == 'data2'
-
- viewer1 = ga.viewers[0][0]
-
- assert len(viewer1.state.layers) == 3
-
- assert viewer1.state.x_att_world is dc[0].id['World 1']
- assert viewer1.state.y_att_world is dc[0].id['World 0']
-
- assert viewer1.state.x_min < -0.5
- assert viewer1.state.x_max > 1.5
- assert viewer1.state.y_min <= -0.5
- assert viewer1.state.y_max >= 1.5
-
- layer_state = viewer1.state.layers[0]
- assert isinstance(layer_state, ImageLayerState)
- assert layer_state.visible
- assert layer_state.bias == 0.5
- assert layer_state.contrast == 1.0
- assert layer_state.stretch == 'sqrt'
- assert layer_state.percentile == 99
-
- layer_state = viewer1.state.layers[1]
- assert isinstance(layer_state, ScatterLayerState)
- assert layer_state.visible
-
- layer_state = viewer1.state.layers[2]
- assert isinstance(layer_state, ImageSubsetLayerState)
- assert not layer_state.visible
-
- viewer2 = ga.viewers[0][1]
-
- assert len(viewer2.state.layers) == 2
-
- assert viewer2.state.x_att_world is dc[0].id['World 1']
- assert viewer2.state.y_att_world is dc[0].id['World 0']
-
- assert viewer2.state.x_min < -0.5
- assert viewer2.state.x_max > 1.5
- assert viewer2.state.y_min <= -0.5
- assert viewer2.state.y_max >= 1.5
-
- layer_state = viewer2.state.layers[0]
- assert layer_state.visible
- assert layer_state.stretch == 'arcsinh'
- assert layer_state.v_min == 1
- assert layer_state.v_max == 4
-
- layer_state = viewer2.state.layers[1]
- assert layer_state.visible
-
- viewer3 = ga.viewers[0][2]
-
- assert len(viewer3.state.layers) == 2
-
- assert viewer3.state.x_att_world is dc[0].id['World 1']
- assert viewer3.state.y_att_world is dc[0].id['World 0']
-
- assert viewer3.state.x_min < -0.5
- assert viewer3.state.x_max > 1.5
- assert viewer3.state.y_min <= -0.5
- assert viewer3.state.y_max >= 1.5
-
- layer_state = viewer3.state.layers[0]
- assert layer_state.visible
- assert layer_state.stretch == 'linear'
- assert layer_state.v_min == -2
- assert layer_state.v_max == 2
-
- layer_state = viewer3.state.layers[1]
- assert layer_state.visible
-
- ga.close()
-
- @pytest.mark.parametrize('protocol', [0, 1])
- def test_session_cube_back_compat(self, protocol):
-
- filename = os.path.join(DATA, 'image_cube_v{0}.glu'.format(protocol))
-
- with open(filename, 'r') as f:
- session = f.read()
-
- state = GlueUnSerializer.loads(session)
-
- ga = state.object('__main__')
-
- dc = ga.session.data_collection
-
- assert len(dc) == 1
-
- assert dc[0].label == 'array'
-
- viewer1 = ga.viewers[0][0]
-
- assert len(viewer1.state.layers) == 1
-
- assert viewer1.state.x_att_world is dc[0].id['World 2']
- assert viewer1.state.y_att_world is dc[0].id['World 1']
- assert viewer1.state.slices == [2, 0, 0, 1]
-
- ga.close()
-
- @pytest.mark.parametrize('protocol', [0, 1])
- def test_session_rgb_back_compat(self, protocol):
-
- filename = os.path.join(DATA, 'image_rgb_v{0}.glu'.format(protocol))
-
- with open(filename, 'r') as f:
- session = f.read()
-
- state = GlueUnSerializer.loads(session)
-
- ga = state.object('__main__')
-
- dc = ga.session.data_collection
-
- assert len(dc) == 1
-
- assert dc[0].label == 'rgbcube'
-
- viewer1 = ga.viewers[0][0]
-
- assert len(viewer1.state.layers) == 3
- assert viewer1.state.color_mode == 'One color per layer'
-
- layer_state = viewer1.state.layers[0]
- assert layer_state.visible
- assert layer_state.attribute.label == 'a'
- assert layer_state.color == 'r'
-
- layer_state = viewer1.state.layers[1]
- assert not layer_state.visible
- assert layer_state.attribute.label == 'c'
- assert layer_state.color == 'g'
-
- layer_state = viewer1.state.layers[2]
- assert layer_state.visible
- assert layer_state.attribute.label == 'b'
- assert layer_state.color == 'b'
-
- ga.close()
-
-
-def test_indexed_data(capsys):
-
- # Make sure that the image viewer works properly with IndexedData objects
-
- data_4d = Data(label='hypercube_wcs',
- x=np.random.random((3, 5, 4, 3)),
- coords=WCS(naxis=4))
-
- data_2d = IndexedData(data_4d, (2, None, 3, None))
-
- application = GlueApplication()
-
- session = application.session
-
- hub = session.hub
-
- data_collection = session.data_collection
- data_collection.append(data_4d)
- data_collection.append(data_2d)
-
- viewer = application.new_data_viewer(ImageViewer)
- viewer.add_data(data_2d)
-
- assert viewer.state.x_att is data_2d.pixel_component_ids[1]
- assert viewer.state.y_att is data_2d.pixel_component_ids[0]
- assert viewer.state.x_att_world is data_2d.world_component_ids[1]
- assert viewer.state.y_att_world is data_2d.world_component_ids[0]
-
- process_events()
-
- application.close()
-
- # Some exceptions used to happen during callbacks, and these show up
- # in stderr but don't interrupt the code, so we make sure here that
- # nothing was printed to stdout nor stderr.
-
- out, err = capsys.readouterr()
-
- assert out.strip() == ""
- assert err.strip() == ""
diff --git a/glue/viewers/image/qt/tests/test_python_export.py b/glue/viewers/image/qt/tests/test_python_export.py
deleted file mode 100644
index cfee1c89a..000000000
--- a/glue/viewers/image/qt/tests/test_python_export.py
+++ /dev/null
@@ -1,126 +0,0 @@
-import pytest
-import numpy as np
-import matplotlib.pyplot as plt
-from astropy.utils import NumpyRNGContext
-from astropy.wcs import WCS
-
-from glue.core import Data, DataCollection
-from glue.core.coordinates import AffineCoordinates
-from glue.app.qt.application import GlueApplication
-from glue.viewers.image.qt import ImageViewer
-from glue.viewers.matplotlib.qt.tests.test_python_export import BaseTestExportPython
-
-
-class TestExportPython(BaseTestExportPython):
-
- def setup_method(self, method):
-
- with NumpyRNGContext(12345):
- self.data = Data(cube=np.random.random((30, 50, 20)))
- # Create data versions with WCS and affine coordinates
- matrix = np.array([[2, 3, 4, -1], [1, 2, 2, 2], [1, 1, 1, -2], [0, 0, 0, 1]])
- affine = AffineCoordinates(matrix, units=['Mm', 'Mm', 'km'], labels=['xw', 'yw', 'zw'])
-
- self.data_wcs = Data(label='cube', cube=self.data['cube'], coords=WCS(naxis=3))
- self.data_affine = Data(label='cube', cube=self.data['cube'], coords=affine)
- self.data_collection = DataCollection([self.data, self.data_wcs, self.data_affine])
- self.app = GlueApplication(self.data_collection)
- self.viewer = self.app.new_data_viewer(ImageViewer)
- self.viewer.add_data(self.data)
- # FIXME: On some platforms, using an integer label size
- # causes some of the labels to be non-deterministically
- # shifted by one pixel, so we pick a non-round font size
- # to avoid this.
- self.viewer.state.x_ticklabel_size = 8.21334111
- self.viewer.state.y_ticklabel_size = 8.21334111
-
- def teardown_method(self, method):
- self.viewer.close()
- self.viewer = None
- self.app.close()
- self.app = None
-
- def assert_same(self, tmpdir, tol=0.1):
- BaseTestExportPython.assert_same(self, tmpdir, tol=tol)
-
- def viewer_load(self, coords):
- if coords is not None:
- self.viewer.add_data(getattr(self, f'data_{coords}'))
- self.viewer.remove_data(self.data)
-
- @pytest.mark.parametrize('coords', [None, 'wcs', 'affine'])
- def test_simple(self, tmpdir, coords):
- self.viewer_load(coords)
- self.assert_same(tmpdir)
-
- @pytest.mark.parametrize('coords', [None, 'wcs', 'affine'])
- def test_simple_legend(self, tmpdir, coords):
- self.viewer_load(coords)
- self.viewer.state.show_legend = True
- self.assert_same(tmpdir)
-
- @pytest.mark.parametrize('coords', [None, 'wcs', 'affine'])
- def test_simple_att(self, tmpdir, coords):
- self.viewer_load(coords)
- self.viewer.state.x_att = self.viewer.state.reference_data.pixel_component_ids[1]
- self.viewer.state.y_att = self.viewer.state.reference_data.pixel_component_ids[0]
- if coords == 'affine':
- pytest.xfail('Known issue with axis label rendering')
- self.assert_same(tmpdir)
-
- @pytest.mark.parametrize('coords', [None, 'wcs', 'affine'])
- def test_simple_visual(self, tmpdir, coords):
- self.viewer_load(coords)
- self.viewer.state.legend.visible = True
- self.viewer.state.layers[0].cmap = plt.cm.RdBu
- self.viewer.state.layers[0].v_min = 0.2
- self.viewer.state.layers[0].v_max = 0.8
- self.viewer.state.layers[0].stretch = 'sqrt'
- self.viewer.state.layers[0].stretch = 'sqrt'
- self.viewer.state.layers[0].contrast = 0.9
- self.viewer.state.layers[0].bias = 0.6
- self.assert_same(tmpdir)
-
- @pytest.mark.parametrize('coords', [None, 'wcs', 'affine'])
- def test_slice(self, tmpdir, coords):
- self.viewer_load(coords)
- self.viewer.state.x_att = self.viewer.state.reference_data.pixel_component_ids[1]
- self.viewer.state.y_att = self.viewer.state.reference_data.pixel_component_ids[0]
- self.viewer.state.slices = (2, 3, 4)
- if coords == 'affine':
- pytest.xfail('Known issue with axis label rendering')
- self.assert_same(tmpdir)
-
- @pytest.mark.parametrize('coords', [None, 'wcs', 'affine'])
- def test_aspect(self, tmpdir, coords):
- self.viewer_load(coords)
- self.viewer.state.aspect = 'auto'
- self.assert_same(tmpdir)
-
- @pytest.mark.parametrize('coords', [None, 'wcs', 'affine'])
- def test_subset(self, tmpdir, coords):
- self.viewer_load(coords)
- self.data_collection.new_subset_group('mysubset', self.data.id['cube'] > 0.5)
- self.assert_same(tmpdir)
-
- @pytest.mark.parametrize('coords', [None, 'wcs', 'affine'])
- def test_subset_legend(self, tmpdir, coords):
- self.viewer_load(coords)
- self.data_collection.new_subset_group('mysubset',
- self.viewer.state.reference_data.id['cube'] > 0.5)
- self.viewer.state.legend.visible = True
- self.assert_same(tmpdir, tol=0.15) # transparency and such
-
- @pytest.mark.parametrize('coords', [None, 'wcs', 'affine'])
- def test_subset_slice(self, tmpdir, coords):
- self.viewer_load(coords)
- self.data_collection.new_subset_group('mysubset', self.data.id['cube'] > 0.5)
- self.test_slice(tmpdir, coords)
-
- @pytest.mark.parametrize('coords', [None, 'wcs', 'affine'])
- def test_subset_transposed(self, tmpdir, coords):
- self.viewer_load(coords)
- self.data_collection.new_subset_group('mysubset', self.data.id['cube'] > 0.5)
- self.viewer.state.x_att = self.data.pixel_component_ids[0]
- self.viewer.state.y_att = self.data.pixel_component_ids[1]
- self.assert_same(tmpdir)
diff --git a/glue/viewers/image/qt/tests/test_regression.py b/glue/viewers/image/qt/tests/test_regression.py
deleted file mode 100644
index d4b07587a..000000000
--- a/glue/viewers/image/qt/tests/test_regression.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Miscellaneous regression tests for the image viewer
-
-import pytest
-import numpy as np
-
-from glue.core import Data
-from glue.viewers.image.qt import ImageViewer
-from glue.core.tests.util import simple_session
-from glue.tests.helpers import PYSIDE2_INSTALLED # noqa
-
-
-@pytest.mark.skipif('PYSIDE2_INSTALLED')
-@pytest.mark.mpl_image_compare(tolerance=1, savefig_kwargs={'dpi': 50})
-def test_resample_on_zoom():
-
- # For images where the aspect ratio of pixels is fixed to be square, when
- # the user zooms in, the limits of the axes are actually changed twice by
- # matplotlib - a second time when the aspect ratio is enforced. So we need
- # to make sure that we update the FRB artist when this is the case.
-
- session = simple_session()
-
- np.random.seed(12345)
-
- data = Data(x=np.random.random((2048, 2048)), label='image')
- session.data_collection.append(data)
-
- image = ImageViewer(session=session)
- image.add_data(data)
-
- image.show()
-
- try:
- device_ratio = image.axes.figure.canvas.devicePixelRatio()
- except AttributeError:
- device_ratio = 1.
-
- image.axes.figure.canvas.key_press_event('o')
- image.axes.figure.canvas.button_press_event(200 * device_ratio, 200 * device_ratio, 1)
- image.axes.figure.canvas.motion_notify_event(400 * device_ratio, 210 * device_ratio)
- image.axes.figure.canvas.button_release_event(400 * device_ratio, 210 * device_ratio, 1)
-
- figure = image.axes.figure
-
- image.close()
-
- return figure
diff --git a/glue/viewers/image/state.py b/glue/viewers/image/state.py
index 0c6ae51b3..ecb1db944 100644
--- a/glue/viewers/image/state.py
+++ b/glue/viewers/image/state.py
@@ -2,7 +2,7 @@
from collections import defaultdict
from glue.core import BaseData
-from glue.config import colormaps
+from glue.config import colormaps, stretches
from glue.viewers.matplotlib.state import (MatplotlibDataViewerState,
MatplotlibLayerState,
DeferredDrawCallbackProperty as DDCProperty,
@@ -525,13 +525,8 @@ def __init__(self, layer=None, viewer_state=None, **kwargs):
ImageLayerState.percentile.set_choices(self, [100, 99.5, 99, 95, 90, 'Custom'])
ImageLayerState.percentile.set_display_func(self, percentile_display.get)
- stretch_display = {'linear': 'Linear',
- 'sqrt': 'Square Root',
- 'arcsinh': 'Arcsinh',
- 'log': 'Logarithmic'}
-
- ImageLayerState.stretch.set_choices(self, ['linear', 'sqrt', 'arcsinh', 'log'])
- ImageLayerState.stretch.set_display_func(self, stretch_display.get)
+ ImageLayerState.stretch.set_choices(self, list(stretches.members))
+ ImageLayerState.stretch.set_display_func(self, stretches.display_func)
self.add_callback('global_sync', self._update_syncing)
self.add_callback('layer', self._update_attribute)
diff --git a/glue/viewers/image/tests/test_composite_array.py b/glue/viewers/image/tests/test_composite_array.py
index 40438ff9e..2ba6d53a2 100644
--- a/glue/viewers/image/tests/test_composite_array.py
+++ b/glue/viewers/image/tests/test_composite_array.py
@@ -66,15 +66,19 @@ def test_cmap_blending(self):
expected_a = np.array([[cm.Blues(1.), cm.Blues(0.5)],
[cm.Blues(0.), cm.Blues(0.)]])
- expected_b = np.array([[cm.Reds(0.), cm.Reds(1.)],
- [cm.Reds(0.), cm.Reds(0.)]])
+ bad_value = cm.Reds.with_extremes(
+ # set "bad" to the default color and alpha=1
+ bad=cm.Reds.get_bad().tolist()[:3] + [1.]
+ )(np.nan)
+ expected_b = np.array(
+ [[bad_value, cm.Reds(1.)],
+ [cm.Reds(0.), cm.Reds(0.)]]
+ )
# If both layers have alpha=1, the top layer should be the only one visible
-
assert_allclose(self.composite(bounds=self.default_bounds), expected_b)
# If the top layer has alpha=0, the bottom layer should be the only one visible
-
self.composite.set('b', alpha=0.)
assert_allclose(self.composite(bounds=self.default_bounds), expected_a)
@@ -96,7 +100,7 @@ def test_cmap_alphas(self):
cmap=cm.Blues, clim=(0, 2))
self.composite.set('b', zorder=1, visible=True, array=self.array2,
- cmap=lambda x: cm.Reds(x, alpha=abs(np.nan_to_num(x))), clim=(0, 1))
+ cmap=lambda x: cm.Reds(x, alpha=abs(x)), clim=(0, 1))
# Determine expected result for each layer individually in the absence
# of transparency
@@ -104,14 +108,18 @@ def test_cmap_alphas(self):
expected_a = np.array([[cm.Blues(1.), cm.Blues(0.5)],
[cm.Blues(0.), cm.Blues(0.)]])
- expected_b = np.array([[cm.Reds(0.), cm.Reds(1.)],
- [cm.Reds(0.), cm.Reds(0.)]])
+ bad_value = cm.Reds.with_extremes(
+ # set "bad" to the default color and alpha=0
+ bad=cm.Reds.get_bad().tolist()[:3] + [0.]
+ )(np.nan)
+ expected_b_1 = np.array([[bad_value, cm.Reds(1.)],
+ [cm.Reds(0.), cm.Reds(0.)]])
# If the top layer has alpha=1 with a colormap alpha fading proportional to absval,
# it should be visible only at the nonzero value [0, 1]
assert_allclose(self.composite(bounds=self.default_bounds),
- [[expected_a[0, 0], expected_b[0, 1]], expected_a[1]])
+ [[expected_a[0, 0], expected_b_1[0, 1]], expected_a[1]])
# For the same case with the top layer alpha=0.5 that value should become an equal
# blend of both layers again
@@ -119,7 +127,7 @@ def test_cmap_alphas(self):
self.composite.set('b', alpha=0.5)
assert_allclose(self.composite(bounds=self.default_bounds),
- [[expected_a[0, 0], 0.5 * (expected_a[0, 1] + expected_b[0, 1])],
+ [[expected_a[0, 0], 0.5 * (expected_a[0, 1] + expected_b_1[0, 1])],
expected_a[1]])
# A third layer added at the bottom should not be visible in the output
@@ -129,21 +137,27 @@ def test_cmap_alphas(self):
cmap=cm.Greens, clim=(0, 2))
assert_allclose(self.composite(bounds=self.default_bounds),
- [[expected_a[0, 0], 0.5 * (expected_a[0, 1] + expected_b[0, 1])],
+ [[expected_a[0, 0], 0.5 * (expected_a[0, 1] + expected_b_1[0, 1])],
expected_a[1]])
# For only the bottom layer having such colormap, the top layer should appear just the same
- self.composite.set('a', alpha=1., cmap=lambda x: cm.Blues(x, alpha=abs(np.nan_to_num(x))))
+ self.composite.set('a', alpha=1., cmap=lambda x: cm.Blues(x, alpha=abs(x)))
self.composite.set('b', alpha=1., cmap=cm.Reds)
- assert_allclose(self.composite(bounds=self.default_bounds), expected_b)
+ bad_value = cm.Reds.with_extremes(
+ # set "bad" to the default color and alpha=1
+ bad=cm.Reds.get_bad().tolist()[:3] + [1.]
+ )(np.nan)
+ expected_b_2 = np.array([[bad_value, cm.Reds(1.)],
+ [cm.Reds(0.), cm.Reds(0.)]])
+ assert_allclose(self.composite(bounds=self.default_bounds), expected_b_2)
- # Settin the third layer on top with alpha=0 should not affect the appearance
+ # Setting the third layer on top with alpha=0 should not affect the appearance
self.composite.set('c', zorder=2, alpha=0.)
- assert_allclose(self.composite(bounds=self.default_bounds), expected_b)
+ assert_allclose(self.composite(bounds=self.default_bounds), expected_b_2)
def test_color_blending(self):
diff --git a/glue/viewers/image/viewer.py b/glue/viewers/image/viewer.py
index 97288583e..02f23e243 100644
--- a/glue/viewers/image/viewer.py
+++ b/glue/viewers/image/viewer.py
@@ -127,7 +127,7 @@ def _set_wcs(self, before=None, after=None, relim=True):
self.state.reset_limits()
# Determine whether changing slices requires changing the WCS
- if ref_coords is None or type(ref_coords) == Coordinates:
+ if ref_coords is None or type(ref_coords) is Coordinates:
self._changing_slice_requires_wcs_update = False
else:
ix = self.state.x_att.axis
diff --git a/glue/viewers/matplotlib/qt/__init__.py b/glue/viewers/matplotlib/qt/__init__.py
index 090d5595a..2d725e620 100644
--- a/glue/viewers/matplotlib/qt/__init__.py
+++ b/glue/viewers/matplotlib/qt/__init__.py
@@ -1 +1,4 @@
-from . import toolbar_mode # noqa
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.matplotlib.qt is deprecated, use glue_qt.viewers.matplotlib instead', GlueDeprecationWarning)
+from glue_qt.viewers.matplotlib import * # noqa
diff --git a/glue/viewers/matplotlib/qt/axes_editor.py b/glue/viewers/matplotlib/qt/axes_editor.py
index d81b3d18f..dbcf092e9 100644
--- a/glue/viewers/matplotlib/qt/axes_editor.py
+++ b/glue/viewers/matplotlib/qt/axes_editor.py
@@ -1,15 +1,4 @@
-import os
-
-from qtpy import QtWidgets
-
-from glue.utils.qt import load_ui
-
-__all__ = ['AxesEditorWidget']
-
-
-class AxesEditorWidget(QtWidgets.QWidget):
-
- def __init__(self, parent=None):
- super(AxesEditorWidget, self).__init__(parent=parent)
- self.ui = load_ui('axes_editor.ui', self,
- directory=os.path.dirname(__file__))
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.matplotlib.qt.axes_editor is deprecated, use glue_qt.viewers.matplotlib.axes_editor instead', GlueDeprecationWarning)
+from glue_qt.viewers.matplotlib.axes_editor import * # noqa
diff --git a/glue/viewers/matplotlib/qt/axes_editor.ui b/glue/viewers/matplotlib/qt/axes_editor.ui
deleted file mode 100644
index eee77d0dd..000000000
--- a/glue/viewers/matplotlib/qt/axes_editor.ui
+++ /dev/null
@@ -1,213 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 272
- 286
-
-
-
- Form
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
- y label:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -
-
-
-
- 70
- 0
-
-
-
-
- -
-
-
- -
-
-
- -
-
-
- x label:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- tick label size
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 70
- 0
-
-
-
-
- -
-
-
- axis label size
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- axis label weight
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 50
- false
-
-
-
- x
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Apply to all plots
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 0
-
-
-
-
- -
-
-
-
- 50
- false
-
-
-
- y
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
-
-
-
diff --git a/glue/viewers/matplotlib/qt/compute_worker.py b/glue/viewers/matplotlib/qt/compute_worker.py
index f2528be88..34e2f794b 100644
--- a/glue/viewers/matplotlib/qt/compute_worker.py
+++ b/glue/viewers/matplotlib/qt/compute_worker.py
@@ -1,62 +1,4 @@
-import sys
-import time
-import queue
-
-from glue.utils import queue_to_list
-from qtpy.QtCore import Signal, QThread
-
-
-# For some viewers, we make use of a thread that continuously listens for
-# requests to update the profile and we run these as needed. In future,
-# we should add the ability to interrupt compute jobs if a newer compute
-# job is requested.
-
-
-class ComputeWorker(QThread):
-
- compute_start = Signal()
- compute_end = Signal()
- compute_error = Signal(object)
-
- def __init__(self, function):
- super(ComputeWorker, self).__init__()
- self.function = function
- self.running = False
- self.work_queue = queue.Queue()
-
- def run(self):
-
- error = None
-
- while True:
-
- time.sleep(1 / 25)
-
- msgs = queue_to_list(self.work_queue)
-
- if 'stop' in msgs:
- return
-
- elif len(msgs) == 0:
- # We change this here rather than in the try...except below
- # to avoid stopping and starting in quick succession.
- if self.running:
- self.running = False
- if error is None:
- self.compute_end.emit()
- else:
- self.compute_error.emit(error)
- error = None
- continue
-
- # If any resets were requested, honor this
- reset = any(msgs)
-
- try:
- self.running = True
- self.compute_start.emit()
- self.function(reset=reset)
- except Exception:
- error = sys.exc_info()
- else:
- error = None
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.matplotlib.qt.compute_worker is deprecated, use glue_qt.viewers.matplotlib.compute_worker instead', GlueDeprecationWarning)
+from glue_qt.viewers.matplotlib.compute_worker import * # noqa
diff --git a/glue/viewers/matplotlib/qt/data_viewer.py b/glue/viewers/matplotlib/qt/data_viewer.py
index 742934034..aa334f43c 100644
--- a/glue/viewers/matplotlib/qt/data_viewer.py
+++ b/glue/viewers/matplotlib/qt/data_viewer.py
@@ -1,76 +1,4 @@
-from qtpy.QtCore import QTimer
-
-from glue.core.message import ComputationStartedMessage
-from glue.viewers.common.qt.data_viewer import DataViewer
-from glue.viewers.matplotlib.qt.widget import MplWidget
-from glue.viewers.matplotlib.mpl_axes import init_mpl
-from glue.utils import defer_draw, decorate_all_methods
-from glue.viewers.matplotlib.state import MatplotlibDataViewerState
-from glue.viewers.matplotlib.viewer import MatplotlibViewerMixin
-
-# The following import is required to register the viewer tools
-from glue.viewers.matplotlib.qt import toolbar # noqa
-
-__all__ = ['MatplotlibDataViewer']
-
-
-@decorate_all_methods(defer_draw)
-class MatplotlibDataViewer(MatplotlibViewerMixin, DataViewer):
-
- _state_cls = MatplotlibDataViewerState
-
- tools = ['mpl:home', 'mpl:pan', 'mpl:zoom']
- subtools = {'save': ['mpl:save']}
-
- def __init__(self, session, parent=None, wcs=None, state=None, projection=None):
-
- super(MatplotlibDataViewer, self).__init__(session, parent=parent, state=state)
-
- # Use MplWidget to set up a Matplotlib canvas inside the Qt window
- self.mpl_widget = MplWidget()
- self.setCentralWidget(self.mpl_widget)
-
- # TODO: shouldn't have to do this
- self.central_widget = self.mpl_widget
-
- self.figure, self.axes = init_mpl(self.mpl_widget.canvas.fig, wcs=wcs, projection=projection)
-
- MatplotlibViewerMixin.setup_callbacks(self)
-
- self.central_widget.resize(600, 400)
- self.resize(self.central_widget.size())
-
- self._monitor_computation = QTimer()
- self._monitor_computation.setInterval(500)
- self._monitor_computation.timeout.connect(self._update_computation)
-
- def _update_computation(self, message=None):
-
- # If we get a ComputationStartedMessage and the timer isn't currently
- # active, then we start the timer but we then return straight away.
- # This is to avoid showing the 'Computing' message straight away in the
- # case of reasonably fast operations.
- if isinstance(message, ComputationStartedMessage):
- if not self._monitor_computation.isActive():
- self._monitor_computation.start()
- return
-
- for layer_artist in self.layers:
- if layer_artist.is_computing:
- self.loading_rectangle.set_visible(True)
- text = self.loading_text.get_text()
- if text.count('.') > 2:
- text = 'Computing'
- else:
- text += '.'
- self.loading_text.set_text(text)
- self.loading_text.set_visible(True)
- self.redraw()
- return
-
- self.loading_rectangle.set_visible(False)
- self.loading_text.set_visible(False)
- self.redraw()
-
- # If we get here, the computation has stopped so we can stop the timer
- self._monitor_computation.stop()
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.matplotlib.qt.data_viewer is deprecated, use glue_qt.viewers.matplotlib.data_viewer instead', GlueDeprecationWarning)
+from glue_qt.viewers.matplotlib.data_viewer import * # noqa
diff --git a/glue/viewers/matplotlib/qt/legend_editor.py b/glue/viewers/matplotlib/qt/legend_editor.py
old mode 100755
new mode 100644
index c4974f04a..762f23046
--- a/glue/viewers/matplotlib/qt/legend_editor.py
+++ b/glue/viewers/matplotlib/qt/legend_editor.py
@@ -1,15 +1,4 @@
-import os
-
-from qtpy import QtWidgets
-
-from glue.utils.qt import load_ui
-
-__all__ = ['LegendEditorWidget']
-
-
-class LegendEditorWidget(QtWidgets.QWidget):
-
- def __init__(self, parent=None):
- super(LegendEditorWidget, self).__init__(parent=parent)
- self.ui = load_ui('legend_editor.ui', self,
- directory=os.path.dirname(__file__))
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.matplotlib.qt.legend_editor is deprecated, use glue_qt.viewers.matplotlib.legend_editor instead', GlueDeprecationWarning)
+from glue_qt.viewers.matplotlib.legend_editor import * # noqa
diff --git a/glue/viewers/matplotlib/qt/legend_editor.ui b/glue/viewers/matplotlib/qt/legend_editor.ui
deleted file mode 100644
index e991e2865..000000000
--- a/glue/viewers/matplotlib/qt/legend_editor.ui
+++ /dev/null
@@ -1,179 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 272
- 286
-
-
-
- Form
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
-
- 0
- 0
-
-
-
- enable
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- location
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -
-
-
- opacity
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- title
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -
-
-
- label size
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -
-
-
- box color
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- text color
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- box edge
-
-
-
-
-
-
-
- QColorBox
- QLabel
-
-
-
-
-
-
diff --git a/glue/viewers/matplotlib/qt/tests/__init__.py b/glue/viewers/matplotlib/qt/tests/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/glue/viewers/matplotlib/qt/tests/test_data_viewer.py b/glue/viewers/matplotlib/qt/tests/test_data_viewer.py
deleted file mode 100644
index 95fc9beee..000000000
--- a/glue/viewers/matplotlib/qt/tests/test_data_viewer.py
+++ /dev/null
@@ -1,681 +0,0 @@
-# pylint: disable=I0011,W0613,W0201,W0212,E1101,E1103
-
-import sys
-
-import pytest
-from numpy.testing import assert_allclose
-
-try:
- import objgraph
-except ImportError:
- OBJGRAPH_INSTALLED = False
-else:
- OBJGRAPH_INSTALLED = True
-
-from glue.core import Data
-from glue.core.exceptions import IncompatibleDataException
-from glue.app.qt.application import GlueApplication
-from glue.core.roi import XRangeROI
-from glue.utils.qt import process_events
-from glue.tests.helpers import requires_matplotlib_ge_22
-
-
-class MatplotlibDrawCounter(object):
-
- def __init__(self, figure):
- self.figure = figure
- # For recent versions of Matplotlib it seems that we need
- # to process events at least twice to really flush out any
- # unprocessed events
- process_events()
- process_events()
- self.start = self.figure.canvas._draw_count
-
- @property
- def draw_count(self):
- process_events()
- process_events()
- return self.figure.canvas._draw_count - self.start
-
-
-class BaseTestMatplotlibDataViewer(object):
- """
- Base class to test viewers based on MatplotlibDataViewer. This only runs
- a subset of tests that relate to functionality implemented in
- MatplotlibDataViewer and specific viewers are responsible for implementing
- a more complete test suite.
-
- Viewers based on this should inherit from this test class and define the
- following attributes:
-
- * ``data``: an instance of a data object that works by default in the viewer
- * ``viewer_cls``: the viewer class
-
- It is then safe to assume that ``data_collection``, ``viewer``, and ``hub``
- are defined when writing tests.
- """
-
- def setup_method(self, method):
-
- if OBJGRAPH_INSTALLED:
- self.viewer_count_start = self.viewer_count
-
- self.data = self.init_data()
-
- self.application = GlueApplication()
- self.session = self.application.session
- self.hub = self.session.hub
-
- self.data_collection = self.session.data_collection
- self.data_collection.append(self.data)
-
- self.viewer = self.viewer_cls(self.session)
-
- self.data_collection.register_to_hub(self.hub)
- self.viewer.register_to_hub(self.hub)
-
- def init_subset(self):
- cid = self.data.main_components[0]
- self.data_collection.new_subset_group('subset 1', cid > 0)
-
- @property
- def viewer_count(self):
- process_events()
- obj = objgraph.by_type(self.viewer_cls.__name__)
- return len(obj)
-
- def teardown_method(self, method):
-
- if self.viewer is not None:
- self.viewer.close()
- self.application.close()
-
- # Matplotlib 3.5 introduced a memory leak when resizing the viewer
- # in https://github.com/matplotlib/matplotlib/pull/19255 so for now
- # we skip the affected test for the objgraph testing
- if method.__name__ == 'test_aspect_resize':
- return
-
- # The following seems to fail on Python 3.10 - to be investigated
- if sys.version_info[:2] >= (3, 10) and method.__name__ == 'test_session_round_trip':
- return
-
- # The following is a check to make sure that once the viewer and
- # application have been closed, there are no leftover references to
- # the data viewer. This was introduced because there were previously
- # circular references that meant that viewer instances were not
- # properly garbage collected, which in turn meant they still reacted
- # in some cases to events.
- if OBJGRAPH_INSTALLED:
- self.viewer = None
- self.application = None
- if self.viewer_count > self.viewer_count_start:
- objgraph.show_backrefs(objgraph.by_type(self.viewer_cls.__name__))
- raise ValueError("No net viewers should be created in tests")
-
- def test_add_data(self):
-
- # Add a dataset with no subsets and make sure the appropriate layer
- # state and layer artists are created
-
- self.viewer.add_data(self.data)
-
- assert len(self.viewer.layers) == 1
- assert self.viewer.layers[0].layer is self.data
-
- assert len(self.viewer.state.layers) == 1
- assert self.viewer.state.layers[0].layer is self.data
-
- def test_add_data_with_subset(self):
-
- # Make sure that if subsets are present in the data, they are added
- # automatically
-
- self.init_subset()
- self.viewer.add_data(self.data)
-
- assert len(self.viewer.layers) == 2
- assert self.viewer.layers[0].layer is self.data
- assert self.viewer.layers[1].layer is self.data.subsets[0]
-
- assert len(self.viewer.state.layers) == 2
- assert self.viewer.state.layers[0].layer is self.data
- assert self.viewer.state.layers[1].layer is self.data.subsets[0]
-
- def test_add_data_then_subset(self):
-
- # Make sure that if a subset is created in a dataset that has already
- # been added to a viewer, the subset gets added
-
- self.viewer.add_data(self.data)
-
- assert len(self.viewer.layers) == 1
- assert self.viewer.layers[0].layer is self.data
-
- assert len(self.viewer.state.layers) == 1
- assert self.viewer.state.layers[0].layer is self.data
-
- self.init_subset()
-
- assert len(self.viewer.layers) == 2
- assert self.viewer.layers[0].layer is self.data
- assert self.viewer.layers[1].layer is self.data.subsets[0]
-
- assert len(self.viewer.state.layers) == 2
- assert self.viewer.state.layers[0].layer is self.data
- assert self.viewer.state.layers[1].layer is self.data.subsets[0]
-
- def init_draw_count(self):
- self.mpl_counter = MatplotlibDrawCounter(self.viewer.axes.figure)
-
- @property
- def draw_count(self):
- return self.mpl_counter.draw_count
-
- def test_single_draw(self):
- # Make sure that the number of draws is kept to a minimum
- self.init_draw_count()
- self.init_subset()
- assert self.draw_count == 0
- self.viewer.add_data(self.data)
- assert self.draw_count == 1
-
- def test_update_subset(self):
-
- self.init_draw_count()
-
- # Check that updating a subset causes the plot to be updated
-
- self.init_subset()
-
- assert self.draw_count == 0
-
- self.viewer.add_data(self.data)
-
- count_before = self.draw_count
-
- # Change the subset
- cid = self.data.main_components[0]
- self.data.subsets[0].subset_state = cid > 1
-
- # Make sure the figure has been redrawn
- assert self.draw_count - count_before > 0
-
- def test_double_add_ignored(self):
- self.viewer.add_data(self.data)
- assert len(self.viewer.state.layers) == 1
- self.viewer.add_data(self.data)
- assert len(self.viewer.state.layers) == 1
-
- def test_removing_data_removes_layer_state(self):
- # Removing data from data collection should remove data from viewer
- self.viewer.add_data(self.data)
- assert len(self.viewer.state.layers) == 1
- self.data_collection.remove(self.data)
- assert len(self.viewer.state.layers) == 0
-
- def test_removing_data_removes_subsets(self):
- # Removing data from data collection should remove subsets from viewer
- self.init_subset()
- self.viewer.add_data(self.data)
- assert len(self.viewer.state.layers) == 2
- self.data_collection.remove(self.data)
- assert len(self.viewer.state.layers) == 0
-
- def test_removing_subset_removes_layers(self):
-
- # Removing a layer artist removes the corresponding layer state. We need
- # to do this with a subset otherwise the viewer is closed
-
- self.init_subset()
- self.viewer.add_data(self.data)
-
- assert len(self.viewer.layers) == 2
- assert len(self.viewer.state.layers) == 2
-
- self.data_collection.remove_subset_group(self.data_collection.subset_groups[0])
-
- assert len(self.viewer.layers) == 1
- assert self.viewer.layers[0].layer is self.data
-
- assert len(self.viewer.state.layers) == 1
- assert self.viewer.state.layers[0].layer is self.data
-
- def test_removing_layer_artist_removes_layer_state(self):
-
- # Removing a layer artist removes the corresponding layer state. We need
- # to do this with a subset otherwise the viewer is closed
-
- self.init_subset()
- self.viewer.add_data(self.data)
-
- assert len(self.viewer.layers) == 2
- assert len(self.viewer.state.layers) == 2
-
- # self.layers is a copy so we need to remove from the original list
- self.viewer._layer_artist_container.remove(self.viewer.layers[1])
-
- assert len(self.viewer.layers) == 1
- assert self.viewer.layers[0].layer is self.data
-
- assert len(self.viewer.state.layers) == 1
- assert self.viewer.state.layers[0].layer is self.data
-
- def test_removing_layer_state_removes_layer_artist(self):
-
- # Removing a layer artist removes the corresponding layer state. We need
- # to do this with a subset otherwise the viewer is closed
-
- self.init_subset()
- self.viewer.add_data(self.data)
-
- assert len(self.viewer.layers) == 2
- assert len(self.viewer.state.layers) == 2
-
- # self.layers is a copy so we need to remove from the original list
- self.viewer.state.layers.pop(1)
-
- assert len(self.viewer.layers) == 1
- assert self.viewer.layers[0].layer is self.data
-
- assert len(self.viewer.state.layers) == 1
- assert self.viewer.state.layers[0].layer is self.data
-
- def test_new_subset_after_remove_data(self):
-
- # Once we remove a dataset, if we make a new subset, it will not be
- # added to the viewer
-
- self.init_subset()
- self.viewer.add_data(self.data)
-
- assert len(self.viewer.layers) == 2
- assert len(self.viewer.state.layers) == 2
-
- self.viewer.state.layers.pop(0)
-
- self.init_subset() # makes a new subset
-
- assert len(self.data.subsets) == 2
-
- assert len(self.viewer.layers) == 1
- assert self.viewer.layers[0].layer is self.data.subsets[0]
-
- assert len(self.viewer.state.layers) == 1
- assert self.viewer.state.layers[0].layer is self.data.subsets[0]
-
- def test_remove_not_present_ignored(self):
- data = Data(label='not in viewer')
- self.viewer.remove_data(data)
-
- def test_limits_sync(self):
-
- viewer_state = self.viewer.state
- axes = self.viewer.axes
-
- if axes.get_adjustable() == 'datalim':
- pytest.xfail()
-
- # Make sure that the viewer state and matplotlib viewer limits and log
- # settings are in sync. We start by modifying the state and making sure
- # that the axes follow.
-
- viewer_state.x_min = 3
- viewer_state.x_max = 9
-
- viewer_state.y_min = -2
- viewer_state.y_max = 3
-
- assert axes.get_xlim() == (3, 9)
- assert axes.get_ylim() == (-2, 3)
- assert axes.get_xscale() == 'linear'
- assert axes.get_yscale() == 'linear'
-
- viewer_state.x_log = True
-
- assert axes.get_xlim() == (3, 9)
- assert axes.get_ylim() == (-2, 3)
- assert axes.get_xscale() == 'log'
- assert axes.get_yscale() == 'linear'
-
- viewer_state.y_log = True
-
- # FIXME: the limits for y don't seem right, should be adjusted because of log?
- assert axes.get_xlim() == (3, 9)
- assert axes.get_ylim() == (-2, 3)
- assert axes.get_xscale() == 'log'
- assert axes.get_yscale() == 'log'
-
- # Check that changing the axes changes the state
-
- # NOTE: at the moment this doesn't work because Matplotlib doesn't
- # emit events for changing xscale/yscale. This isn't crucial anyway for
- # glue, but leaving the tests below in case this is fixed some day. The
- # Matplotlib issue is https://github.com/matplotlib/matplotlib/issues/8439
-
- # axes.set_xscale('linear')
- #
- # assert viewer_state.x_min == 3
- # assert viewer_state.x_max == 9
- # assert viewer_state.y_min == -2
- # assert viewer_state.y_max == 3
- # assert not viewer_state.x_log
- # assert viewer_state.y_log
- #
- # axes.set_yscale('linear')
- #
- # assert viewer_state.x_min == 3
- # assert viewer_state.x_max == 9
- # assert viewer_state.y_min == -2
- # assert viewer_state.y_max == 3
- # assert not viewer_state.x_log
- # assert not viewer_state.y_log
-
- viewer_state.x_log = False
- viewer_state.y_log = False
-
- axes.set_xlim(-1, 4)
-
- assert viewer_state.x_min == -1
- assert viewer_state.x_max == 4
- assert viewer_state.y_min == -2
- assert viewer_state.y_max == 3
- # assert not viewer_state.x_log
- # assert not viewer_state.y_log
-
- axes.set_ylim(5, 6)
-
- assert viewer_state.x_min == -1
- assert viewer_state.x_max == 4
- assert viewer_state.y_min == 5
- assert viewer_state.y_max == 6
- # assert not viewer_state.x_log
- # assert not viewer_state.y_log
-
- # TODO: the following test should deal gracefully with the fact that
- # some viewers will want to show a Qt error for IncompatibleDataException
- def test_add_invalid_data(self):
- data2 = Data()
- with pytest.raises(IncompatibleDataException):
- self.viewer.add_data(data2)
-
- # Communication tests
-
- def test_ignore_data_add_message(self):
- self.data_collection.append(self.data)
- assert len(self.viewer.layers) == 0
-
- def test_update_data_ignored_if_data_not_present(self):
- self.init_draw_count()
- self.data_collection.append(self.data)
- ct0 = self.draw_count
- self.data.style.color = 'blue'
- assert self.draw_count == ct0
-
- def test_update_data_processed_if_data_present(self):
- self.init_draw_count()
- self.data_collection.append(self.data)
- self.viewer.add_data(self.data)
- ct0 = self.draw_count
- self.data.style.color = 'blue'
- assert self.draw_count > ct0
-
- def test_add_subset_ignored_if_data_not_present(self):
- self.data_collection.append(self.data)
- sub = self.data.new_subset()
- assert sub not in self.viewer._layer_artist_container
-
- def test_add_subset_processed_if_data_present(self):
- self.data_collection.append(self.data)
- self.viewer.add_data(self.data)
- sub = self.data.new_subset()
- assert sub in self.viewer._layer_artist_container
-
- def test_update_subset_ignored_if_not_present(self):
- # This can be quite a difficult test to pass because it makes sure that
- # there are absolutely no references to the layer state left over once
- # a subset is removed - when originally written this identified quite
- # a few places where references were being accidentally kept, and
- # resulted in weakref being needed in a number of places. But ultimately
- # this test should pass! No cheating :)
- self.init_draw_count()
- self.data_collection.append(self.data)
- self.viewer.add_data(self.data)
- sub = self.data.new_subset()
- self.viewer.remove_subset(sub)
- ct0 = self.draw_count
- sub.style.color = 'blue'
- assert self.draw_count == ct0
-
- def test_update_subset_processed_if_present(self):
- self.init_draw_count()
- self.data_collection.append(self.data)
- self.viewer.add_data(self.data)
- sub = self.data.new_subset()
- ct0 = self.draw_count
- sub.style.color = 'blue'
- assert self.draw_count > ct0
-
- def test_data_remove_message(self):
- self.data_collection.append(self.data)
- self.viewer.add_data(self.data)
- self.data_collection.remove(self.data)
- assert self.data not in self.viewer._layer_artist_container
-
- def test_subset_remove_message(self):
- self.data_collection.append(self.data)
- self.viewer.add_data(self.data)
- sub = self.data.new_subset()
- assert sub in self.viewer._layer_artist_container
- sub.delete()
- assert sub not in self.viewer._layer_artist_container
-
- def test_session_round_trip(self, tmpdir):
-
- self.init_subset()
-
- ga = GlueApplication(self.data_collection)
- ga.show()
-
- viewer = ga.new_data_viewer(self.viewer_cls)
- viewer.add_data(self.data)
-
- session_file = tmpdir.join('test_session_round_trip.glu').strpath
- ga.save_session(session_file)
- ga.close()
-
- ga2 = GlueApplication.restore_session(session_file)
- ga2.show()
-
- viewer2 = ga2.viewers[0][0]
-
- data2 = ga2.data_collection[0]
-
- assert viewer2.layers[0].layer is data2
- assert viewer2.layers[1].layer is data2.subsets[0]
-
- ga2.close()
-
- def test_apply_roi_undo(self):
-
- self.data_collection.append(self.data)
- self.viewer.add_data(self.data)
-
- roi = XRangeROI(1, 2)
- self.viewer.apply_roi(roi)
-
- assert len(self.data.subsets) == 1
-
- lo1 = self.data.subsets[0].subset_state.lo
- hi1 = self.data.subsets[0].subset_state.hi
-
- roi = XRangeROI(0, 3)
- self.viewer.apply_roi(roi)
-
- assert len(self.data.subsets) == 1
-
- lo2 = self.data.subsets[0].subset_state.lo
- hi2 = self.data.subsets[0].subset_state.hi
-
- assert lo2 != lo1
- assert hi2 != hi1
-
- self.application.undo()
-
- assert len(self.data.subsets) == 1
-
- assert self.data.subsets[0].subset_state.lo == lo1
- assert self.data.subsets[0].subset_state.hi == hi1
-
- self.application.redo()
-
- assert len(self.data.subsets) == 1
-
- assert self.data.subsets[0].subset_state.lo == lo2
- assert self.data.subsets[0].subset_state.hi == hi2
-
- def test_numerical_data_changed(self):
- self.init_draw_count()
- self.init_subset()
- assert self.draw_count == 0
- self.viewer.add_data(self.data)
- assert self.draw_count == 1
- data = Data(label=self.data.label)
- data.coords = self.data.coords
- for cid in self.data.main_components:
- if self.data.get_kind(cid) == 'numerical':
- data.add_component(self.data[cid] * 2, cid.label)
- else:
- data.add_component(self.data[cid], cid.label)
- self.data.update_values_from_data(data)
- assert self.draw_count == 2
-
- @requires_matplotlib_ge_22
- def test_aspect_resize(self):
-
- # Make sure that the limits are adjusted appropriately when resizing
- # depending on the aspect ratio mode. Note that we don't add any data
- # here since it isn't needed for this test.
-
- # This test works with Matplotlib 2.0 and 2.2 but not 2.1, hence we
- # skip it with Matplotlib 2.1 above.
-
- # Note that we need to explicitly call draw() below because otherwise
- # draw_idle is used, which has no guarantee of being effective.
-
- # Set initial limits to deterministic values
- self.viewer.state.aspect = 'auto'
- self.viewer.state.x_min = 0.
- self.viewer.state.x_max = 1.
- self.viewer.state.y_min = 0.
- self.viewer.state.y_max = 1.
-
- self.viewer.state.aspect = 'equal'
-
- # Resize events only work if widget is visible
- self.viewer.show()
- self.viewer.figure.canvas.draw()
- process_events(wait=0.1)
-
- def limits(viewer):
- return (viewer.state.x_min, viewer.state.x_max,
- viewer.state.y_min, viewer.state.y_max)
-
- # Set viewer to an initial size and save limits
- self.viewer.viewer_size = (800, 400)
- self.viewer.figure.canvas.draw()
- process_events(wait=0.1)
- initial_limits = limits(self.viewer)
-
- # Change the viewer size, and make sure the limits are adjusted
- self.viewer.viewer_size = (400, 400)
- self.viewer.figure.canvas.draw()
- process_events(wait=0.1)
- with pytest.raises(AssertionError):
- assert_allclose(limits(self.viewer), initial_limits)
-
- # Now change the viewer size a number of times and make sure if we
- # return to the original size, the limits match the initial ones.
- self.viewer.viewer_size = (350, 800)
- self.viewer.figure.canvas.draw()
- process_events(wait=0.1)
- self.viewer.viewer_size = (900, 300)
- self.viewer.figure.canvas.draw()
- process_events(wait=0.1)
- self.viewer.viewer_size = (600, 600)
- self.viewer.figure.canvas.draw()
- process_events(wait=0.1)
- self.viewer.viewer_size = (800, 400)
- self.viewer.figure.canvas.draw()
- process_events(wait=0.1)
- assert_allclose(limits(self.viewer), initial_limits)
-
- # Now check that the limits don't change in 'auto' mode
- self.viewer.state.aspect = 'auto'
- self.viewer.viewer_size = (900, 300)
- self.viewer.figure.canvas.draw()
- process_events(wait=0.1)
- assert_allclose(limits(self.viewer), initial_limits)
-
- def test_update_data_values(self):
-
- # Regression test for a bug that caused some viewers to not behave
- # correctly if the data values were updated.
-
- self.viewer.add_data(self.data)
-
- data = self.init_data()
- self.data_collection.append(data)
-
- self.data.update_values_from_data(data)
-
- def test_legend(self):
- viewer_state = self.viewer.state
-
- self.viewer.add_data(self.data)
-
- # no legend by default
- assert self.viewer.axes.get_legend() is None
-
- self.viewer.state.legend.visible = True
-
- # a legend appears
- legend = self.viewer.axes.get_legend()
- assert not (legend is None)
-
- handles, labels, handler_dict = self.viewer.get_handles_legend()
- assert len(handles) == 1
- assert labels[0] == self.data.label
-
- self.init_subset()
- assert len(viewer_state.layers) == 2
- handles, labels, handler_dict = self.viewer.get_handles_legend()
- assert len(handles) == 2
- assert labels[1] == 'subset 1'
-
- # The next set of test check that the legend does not create extra draws !
- def test_legend_single_draw(self):
- # Make sure that the number of draws is kept to a minimum
- self.viewer.state.legend.visible = True
- self.init_draw_count()
- self.init_subset()
- assert self.draw_count == 0
- self.viewer.add_data(self.data)
- assert self.draw_count == 1
-
- def test_legend_numerical_data_changed(self):
- self.viewer.state.legend.visible = True
- self.init_draw_count()
- self.init_subset()
- assert self.draw_count == 0
- self.viewer.add_data(self.data)
- assert self.draw_count == 1
- data = Data(label=self.data.label)
- data.coords = self.data.coords
- for cid in self.data.main_components:
- if self.data.get_kind(cid) == 'numerical':
- data.add_component(self.data[cid] * 2, cid.label)
- else:
- data.add_component(self.data[cid], cid.label)
- self.data.update_values_from_data(data)
- assert self.draw_count == 2
diff --git a/glue/viewers/matplotlib/qt/tests/test_python_export.py b/glue/viewers/matplotlib/qt/tests/test_python_export.py
deleted file mode 100644
index 24213c8f2..000000000
--- a/glue/viewers/matplotlib/qt/tests/test_python_export.py
+++ /dev/null
@@ -1,62 +0,0 @@
-import os
-import sys
-import pytest
-import subprocess
-
-from glue.config import settings
-
-import numpy as np
-
-from matplotlib.testing.compare import compare_images
-
-__all__ = ['random_with_nan', 'BaseTestExportPython']
-
-
-def random_with_nan(nsamples, nan_index):
- x = np.random.random(nsamples)
- x[nan_index] = np.nan
- return x
-
-
-class BaseTestExportPython:
-
- def assert_same(self, tmpdir, tol=0.1):
-
- os.chdir(tmpdir.strpath)
-
- expected = tmpdir.join('expected.png').strpath
- script = tmpdir.join('actual.py').strpath
- actual = tmpdir.join('glue_plot.png').strpath
-
- self.viewer.axes.figure.savefig(expected)
-
- self.viewer.export_as_script(script)
- subprocess.call([sys.executable, script])
-
- msg = compare_images(expected, actual, tol=tol)
-
- if msg:
-
- from base64 import b64encode
-
- print("SCRIPT:")
- with open(script, 'r') as f:
- print(f.read())
-
- print("EXPECTED:")
- with open(expected, 'rb') as f:
- print(b64encode(f.read()).decode())
-
- print("ACTUAL:")
- with open(actual, 'rb') as f:
- print(b64encode(f.read()).decode())
-
- pytest.fail(msg, pytrace=False)
-
- def test_color_settings(self, tmpdir):
- settings.FOREGROUND_COLOR = '#a51d2d'
- settings.BACKGROUND_COLOR = '#99c1f1'
- self.viewer._update_appearance_from_settings()
- self.assert_same(tmpdir)
- settings.reset_defaults()
- self.viewer._update_appearance_from_settings()
diff --git a/glue/viewers/matplotlib/qt/tests/test_toolbar.py b/glue/viewers/matplotlib/qt/tests/test_toolbar.py
deleted file mode 100644
index b7142b72d..000000000
--- a/glue/viewers/matplotlib/qt/tests/test_toolbar.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# pylint: disable=I0011,W0613,W0201,W0212,E1101,E1103
-
-from glue.viewers.matplotlib.qt.data_viewer import MatplotlibDataViewer
-from glue.viewers.matplotlib.toolbar_mode import ToolbarModeBase
-from glue.core.tests.util import simple_session
-
-
-class ToolbarModeTest(ToolbarModeBase):
-
- tool_id = 'test'
- tool_tip = 'just testing'
- icon = 'glue_square'
-
- def __init__(self, axes, release_callback=None):
- super(ToolbarModeTest, self).__init__(axes, release_callback=release_callback)
- self.action_text = 'test text'
- self.last_mode = None
-
- def press(self, event):
- self.last_mode = 'PRESS'
-
- def move(self, event):
- self.last_mode = 'MOVE'
-
-
-class ExampleViewer(MatplotlibDataViewer):
-
- def __init__(self, session, parent=None):
- super(ExampleViewer, self).__init__(session, parent=parent)
- self.axes.plot([1, 2, 3])[0]
-
- def initialize_toolbar(self):
- super(ExampleViewer, self).initialize_toolbar()
- self.tool = ToolbarModeTest(self, release_callback=self.callback)
- self.toolbar.add_tool(self.tool)
-
- def callback(self, mode):
- self._called_back = True
-
-
-class TestToolbar(object):
-
- def setup_method(self, method):
- self.session = simple_session()
- self.viewer = ExampleViewer(self.session)
- self._called_back = False
-
- def teardown_method(self, method):
- self.viewer.close()
-
- def assert_valid_mode_state(self, target_mode):
- for tool_id in self.viewer.toolbar.actions:
- if tool_id == target_mode and self.viewer.toolbar.actions[tool_id].isCheckable():
- assert self.viewer.toolbar.actions[tool_id].isChecked()
- self.viewer.toolbar._active == target_mode
- else:
- assert not self.viewer.toolbar.actions[tool_id].isChecked()
-
- def test_callback(self):
- self.viewer.toolbar.actions['mpl:home'].trigger()
- self.viewer.tool.release(None)
- assert self.viewer._called_back
-
- def test_change_mode(self):
-
- self.viewer.toolbar.actions['mpl:pan'].toggle()
- assert self.viewer.toolbar.active_tool.tool_id == 'mpl:pan'
- assert self.viewer._mpl_nav.mode == 'pan/zoom'
-
- self.viewer.toolbar.actions['mpl:pan'].toggle()
- assert self.viewer.toolbar.active_tool is None
- assert self.viewer._mpl_nav.mode == ''
-
- self.viewer.toolbar.actions['mpl:zoom'].trigger()
- assert self.viewer.toolbar.active_tool.tool_id == 'mpl:zoom'
- assert self.viewer._mpl_nav.mode == 'zoom rect'
-
- self.viewer.toolbar.actions['test'].trigger()
- assert self.viewer.toolbar.active_tool.tool_id == 'test'
- assert self.viewer._mpl_nav.mode == ''
diff --git a/glue/viewers/matplotlib/qt/tests/test_toolbar_mode.py b/glue/viewers/matplotlib/qt/tests/test_toolbar_mode.py
deleted file mode 100644
index b1500b148..000000000
--- a/glue/viewers/matplotlib/qt/tests/test_toolbar_mode.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from glue.viewers.matplotlib.tests.test_mouse_mode import TestMouseMode, Event
-
-from ..toolbar_mode import ContrastMode
-
-
-class TestContrastMode(TestMouseMode):
-
- def mode_factory(self):
- return ContrastMode
-
- def test_move_ignored_if_not_right_drag(self):
- e = Event(1, 2, button=1)
- self.mode.move(e)
- count = self.mode._axes.figure.canvas.get_width_height.call_count
- assert count == 0
-
- def test_clip_percentile(self):
- assert self.mode.get_clip_percentile() == (1, 99)
- self.mode.set_clip_percentile(2, 33)
- assert self.mode.get_clip_percentile() == (2, 33)
-
- def test_vmin_vmax(self):
- assert self.mode.get_vmin_vmax() == (None, None)
- self.mode.set_vmin_vmax(3, 4)
- assert self.mode.get_vmin_vmax() == (3, 4)
- assert self.mode.get_clip_percentile() == (None, None)
-
- # TODO: at the moment, this doesn't work because the dialog is non-modal
- # assert self.mode.get_vmin_vmax() == (5, 7)
- # def test_choose_vmin_vmax(self):
- #
- # assert self.mode.get_vmin_vmax() == (None, None)
- #
- # def fill_apply(dialog):
- # dialog.vmin.setText('5')
- # dialog.vmax.setText('7')
- # dialog.accept()
- #
- # with process_dialog(delay=500, function=fill_apply):
- # self.mode.choose_vmin_vmax()
diff --git a/glue/viewers/matplotlib/qt/toolbar.py b/glue/viewers/matplotlib/qt/toolbar.py
index 89e1425c4..c2ec8c2be 100644
--- a/glue/viewers/matplotlib/qt/toolbar.py
+++ b/glue/viewers/matplotlib/qt/toolbar.py
@@ -1,109 +1,4 @@
-from matplotlib.backends.backend_qt5 import NavigationToolbar2QT
-
-from glue.config import viewer_tool
-from glue.viewers.common.tool import CheckableTool, Tool
-
-
-__all__ = ['MatplotlibTool', 'MatplotlibCheckableTool', 'HomeTool', 'SaveTool',
- 'PanTool', 'ZoomTool']
-
-
-def _ensure_mpl_nav(viewer):
- # Set up virtual Matplotlib navigation toolbar (don't show it)
- if not hasattr(viewer, '_mpl_nav'):
- viewer._mpl_nav = NavigationToolbar2QT(viewer.central_widget.canvas, viewer)
- viewer._mpl_nav.hide()
-
-
-def _cleanup_mpl_nav(viewer):
- if getattr(viewer, '_mpl_nav', None) is not None:
- viewer._mpl_nav.setParent(None)
- try:
- viewer._mpl_nav.parent = None
- except AttributeError:
- pass
- viewer._mpl_nav = None
-
-
-class MatplotlibTool(Tool):
-
- def __init__(self, viewer=None):
- super(MatplotlibTool, self).__init__(viewer=viewer)
- _ensure_mpl_nav(viewer)
-
- def close(self):
- _cleanup_mpl_nav(self.viewer)
- super(MatplotlibTool, self).close()
-
-
-class MatplotlibCheckableTool(CheckableTool):
-
- def __init__(self, viewer=None):
- super(MatplotlibCheckableTool, self).__init__(viewer=viewer)
- _ensure_mpl_nav(viewer)
-
- def close(self):
- _cleanup_mpl_nav(self.viewer)
- super(MatplotlibCheckableTool, self).close()
-
-
-@viewer_tool
-class HomeTool(MatplotlibTool):
-
- tool_id = 'mpl:home'
- icon = 'glue_home'
- action_text = 'Home'
- tool_tip = 'Reset original zoom'
- shortcut = 'H'
-
- def activate(self):
- if hasattr(self.viewer, 'state') and hasattr(self.viewer.state, 'reset_limits'):
- self.viewer.state.reset_limits()
- else:
- self.viewer._mpl_nav.home()
-
-
-@viewer_tool
-class SaveTool(MatplotlibTool):
-
- tool_id = 'mpl:save'
- icon = 'glue_filesave'
- action_text = 'Save plot to file'
- tool_tip = 'Save the figure'
-
- def activate(self):
- self.viewer._mpl_nav.save_figure()
-
-
-@viewer_tool
-class PanTool(MatplotlibCheckableTool):
-
- tool_id = 'mpl:pan'
- icon = 'glue_move'
- action_text = 'Pan'
- tool_tip = 'Pan axes with left mouse, zoom with right'
- shortcut = 'M'
-
- def activate(self):
- self.viewer._mpl_nav.pan()
-
- def deactivate(self):
- if hasattr(self.viewer, '_mpl_nav'):
- self.viewer._mpl_nav.pan()
-
-
-@viewer_tool
-class ZoomTool(MatplotlibCheckableTool):
-
- tool_id = 'mpl:zoom'
- icon = 'glue_zoom_to_rect'
- action_text = 'Zoom'
- tool_tip = 'Zoom to rectangle'
- shortcut = 'Z'
-
- def activate(self):
- self.viewer._mpl_nav.zoom()
-
- def deactivate(self):
- if hasattr(self.viewer, '_mpl_nav'):
- self.viewer._mpl_nav.zoom()
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.matplotlib.qt.toolbar is deprecated, use glue_qt.viewers.matplotlib.toolbar instead', GlueDeprecationWarning)
+from glue_qt.viewers.matplotlib.toolbar import * # noqa
diff --git a/glue/viewers/matplotlib/qt/toolbar_mode.py b/glue/viewers/matplotlib/qt/toolbar_mode.py
index c7c650149..69af6a89e 100644
--- a/glue/viewers/matplotlib/qt/toolbar_mode.py
+++ b/glue/viewers/matplotlib/qt/toolbar_mode.py
@@ -1,198 +1,4 @@
-import os
-
-from qtpy import QtGui, QtWidgets
-from glue.utils import nonpartial
-from glue.utils.qt import load_ui, cmap2pixmap
-from glue.viewers.common.tool import Tool
-from glue.config import viewer_tool
-from glue.viewers.matplotlib.toolbar_mode import ToolbarModeBase
-
-__all__ = ['ContrastMode', 'ColormapMode']
-
-
-@viewer_tool
-class ContrastMode(ToolbarModeBase):
- """
- Uses right mouse button drags to set bias and contrast, DS9-style.
-
- The horizontal position of the mouse sets the bias, the vertical position
- sets the contrast.
-
- The move_callback defaults to calling _set_norm on the viewer with the
- instance of ConstrastMode as the sole argument.
- """
-
- icon = 'glue_contrast'
- tool_id = 'image:contrast'
- action_text = 'Contrast'
- tool_tip = 'Adjust the bias/contrast'
- shortcut = 'B'
-
- def __init__(self, viewer, **kwargs):
-
- super(ContrastMode, self).__init__(viewer, **kwargs)
-
- self.bias = 0.5
- self.contrast = 1.0
-
- self._last = None
- self._result = None
- self._percent_lo = 1.
- self._percent_hi = 99.
- self.stretch = 'linear'
- self._vmin = None
- self._vmax = None
-
- def set_clip_percentile(self, lo, hi):
- """Percentiles at which to clip the data at black/white"""
- if lo == self._percent_lo and hi == self._percent_hi:
- return
- self._percent_lo = lo
- self._percent_hi = hi
- self._vmin = None
- self._vmax = None
-
- def get_clip_percentile(self):
- if self._vmin is None and self._vmax is None:
- return self._percent_lo, self._percent_hi
- return None, None
-
- def get_vmin_vmax(self):
- if self._percent_lo is None or self._percent_hi is None:
- return self._vmin, self._vmax
- return None, None
-
- def set_vmin_vmax(self, vmin, vmax):
- if vmin == self._vmin and vmax == self._vmax:
- return
- self._percent_hi = self._percent_lo = None
- self._vmin = vmin
- self._vmax = vmax
-
- def choose_vmin_vmax(self):
- dialog = load_ui('contrastlimits.ui', None,
- directory=os.path.dirname(__file__))
- v = QtGui.QDoubleValidator()
- dialog.vmin.setValidator(v)
- dialog.vmax.setValidator(v)
-
- vmin, vmax = self.get_vmin_vmax()
- if vmin is not None:
- dialog.vmin.setText(str(vmin))
- if vmax is not None:
- dialog.vmax.setText(str(vmax))
-
- def _apply():
- try:
- vmin = float(dialog.vmin.text())
- vmax = float(dialog.vmax.text())
- self.set_vmin_vmax(vmin, vmax)
- if self._move_callback is not None:
- self._move_callback(self)
- except ValueError:
- pass
-
- bb = dialog.buttonBox
- bb.button(bb.Apply).clicked.connect(_apply)
- dialog.accepted.connect(_apply)
- dialog.show()
- dialog.raise_()
- dialog.exec_()
-
- def move(self, event):
- """ MoveEvent. Update bias and contrast on Right Mouse button drag """
- if event.button != 3: # RMB drag only
- return
- x, y = event.x, event.y
- dx, dy = self._axes.figure.canvas.get_width_height()
- x = 1.0 * x / dx
- y = 1.0 * y / dy
-
- self.bias = x
- self.contrast = (1 - y) * 10
-
- super(ContrastMode, self).move(event)
-
- def menu_actions(self):
- result = []
-
- a = QtWidgets.QAction("minmax", None)
- a.triggered.connect(nonpartial(self.set_clip_percentile, 0, 100))
- result.append(a)
-
- a = QtWidgets.QAction("99%", None)
- a.triggered.connect(nonpartial(self.set_clip_percentile, 1, 99))
- result.append(a)
-
- a = QtWidgets.QAction("95%", None)
- a.triggered.connect(nonpartial(self.set_clip_percentile, 5, 95))
- result.append(a)
-
- a = QtWidgets.QAction("90%", None)
- a.triggered.connect(nonpartial(self.set_clip_percentile, 10, 90))
- result.append(a)
-
- rng = QtWidgets.QAction("Set range...", None)
- rng.triggered.connect(nonpartial(self.choose_vmin_vmax))
- result.append(rng)
-
- a = QtWidgets.QAction("", None)
- a.setSeparator(True)
- result.append(a)
-
- a = QtWidgets.QAction("linear", None)
- a.triggered.connect(nonpartial(setattr, self, 'stretch', 'linear'))
- result.append(a)
-
- a = QtWidgets.QAction("log", None)
- a.triggered.connect(nonpartial(setattr, self, 'stretch', 'log'))
- result.append(a)
-
- a = QtWidgets.QAction("sqrt", None)
- a.triggered.connect(nonpartial(setattr, self, 'stretch', 'sqrt'))
- result.append(a)
-
- a = QtWidgets.QAction("asinh", None)
- a.triggered.connect(nonpartial(setattr, self, 'stretch', 'arcsinh'))
- result.append(a)
-
- for r in result:
- if r is rng:
- continue
- if self._move_callback is not None:
- r.triggered.connect(nonpartial(self._move_callback, self))
-
- return result
-
-
-class ColormapAction(QtWidgets.QAction):
-
- def __init__(self, label, cmap, parent):
- super(ColormapAction, self).__init__(label, parent)
- self.cmap = cmap
- pm = cmap2pixmap(cmap)
- self.setIcon(QtGui.QIcon(pm))
-
-
-@viewer_tool
-class ColormapMode(Tool):
- """
- A tool to change the colormap used in a viewer.
-
- This calls a ``set_cmap`` method on the viewer, which should take the name
- of the colormap as the sole argument.
- """
-
- icon = 'glue_rainbow'
- tool_id = 'image:colormap'
- action_text = 'Set color scale'
- tool_tip = 'Set color scale'
-
- def menu_actions(self):
- from glue import config
- acts = []
- for label, cmap in config.colormaps:
- a = ColormapAction(label, cmap, self.viewer)
- a.triggered.connect(nonpartial(self.viewer.set_cmap, cmap))
- acts.append(a)
- return acts
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.matplotlib.qt.toolbar_mode is deprecated, use glue_qt.viewers.matplotlib.toolbar_mode instead', GlueDeprecationWarning)
+from glue_qt.viewers.matplotlib.toolbar_mode import * # noqa
diff --git a/glue/viewers/matplotlib/qt/widget.py b/glue/viewers/matplotlib/qt/widget.py
old mode 100755
new mode 100644
index 5010b13bf..d9b1a89ac
--- a/glue/viewers/matplotlib/qt/widget.py
+++ b/glue/viewers/matplotlib/qt/widget.py
@@ -1,181 +1,4 @@
-#!/usr/bin/env python
-
import warnings
-import matplotlib
-from matplotlib.backend_bases import KeyEvent, MouseEvent, ResizeEvent
-from matplotlib.figure import Figure
-
-from qtpy import QtCore, QtGui, QtWidgets
-from qtpy.QtCore import Qt, QRectF
-from glue.config import settings
-from glue.utils.matplotlib import DEFER_DRAW_BACKENDS, MATPLOTLIB_GE_36
-
-from matplotlib.backends.backend_qt5 import FigureManagerQT
-from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
-
-__all__ = ['MplCanvas', 'MplWidget']
-
-# Register the Qt backend with defer_draw
-DEFER_DRAW_BACKENDS.append(FigureCanvasQTAgg)
-
-# We want to ignore warnings about left==right and bottom==top since these are
-# not critical and the default behavior makes sense.
-warnings.filterwarnings('ignore', '.*Attempting to set identical left==right', UserWarning)
-warnings.filterwarnings('ignore', '.*Attempting to set identical bottom==top', UserWarning)
-
-
-class MplCanvas(FigureCanvasQTAgg):
-
- """Class to represent the FigureCanvas widget"""
-
- rightDrag = QtCore.Signal(float, float)
- leftDrag = QtCore.Signal(float, float)
- homeButton = QtCore.Signal()
- resize_begin = QtCore.Signal()
- resize_end = QtCore.Signal()
-
- def __init__(self):
-
- self._draw_count = 0
- interactive = matplotlib.is_interactive()
- matplotlib.interactive(False)
- self.roi_callback = None
-
- self._draw_zoom_rect = None
-
- self.fig = Figure(facecolor=settings.BACKGROUND_COLOR)
-
- FigureCanvasQTAgg.__init__(self, self.fig)
- FigureCanvasQTAgg.setSizePolicy(self,
- QtWidgets.QSizePolicy.Expanding,
- QtWidgets.QSizePolicy.Expanding)
-
- FigureCanvasQTAgg.updateGeometry(self)
- self.manager = FigureManagerQT(self, 0)
- matplotlib.interactive(interactive)
-
- self._resize_timer = QtCore.QTimer()
- self._resize_timer.setInterval(250)
- self._resize_timer.setSingleShot(True)
- self._resize_timer.timeout.connect(self._on_timeout)
-
- self.renderer = None
-
- def _on_timeout(self):
- buttons = QtWidgets.QApplication.instance().mouseButtons()
- if buttons != Qt.NoButton:
- self._resize_timer.start()
- else:
- self.resize_end.emit()
-
- def paintEvent(self, event):
-
- # super needs this
- if self.renderer is None:
- self.renderer = self.get_renderer()
-
- super(MplCanvas, self).paintEvent(event)
-
- # See drawRectangle for what _draw_zoom_rect is
- if self._draw_zoom_rect is not None:
- painter = QtGui.QPainter(self)
- self._draw_zoom_rect(painter)
- painter.end()
-
- if self.roi_callback is not None:
- self.roi_callback(self)
-
- def drawRectangle(self, rect):
-
- # The default zoom rectangle in Matplotlib is quite faint, and there is
- # no easy mechanism for changing the default appearance. However, the
- # drawing of the zoom rectangle is done in the public method
- # drawRectangle on the canvas. This method sets up a callback function
- # that is then called during paintEvent. However, we shouldn't use the
- # same private attribute since this might break, so we use a private
- # attribute with a different name, which means the one matplotlib uses
- # will remain empty and not plot anything.
-
- if rect is None:
- _draw_zoom_rect = None
- else:
- def _draw_zoom_rect(painter):
- pen = QtGui.QPen(QtGui.QPen(Qt.red, 2, Qt.DotLine))
- painter.setPen(pen)
- try:
- dpi_ratio = self.devicePixelRatio() or 1
- except AttributeError: # Matplotlib <2
- dpi_ratio = 1
- painter.drawRect(QRectF(*(pt / dpi_ratio for pt in rect)))
-
- # This function will be called at the end of the paintEvent
- self._draw_zoom_rect = _draw_zoom_rect
-
- # We need to call update to force the canvas to be painted again
- self.update()
-
- def resizeEvent(self, event):
- if not self._resize_timer.isActive():
- self.resize_begin.emit()
- self._resize_timer.start()
- super(MplCanvas, self).resizeEvent(event)
-
- def draw(self, *args, **kwargs):
- self._draw_count += 1
- return super(MplCanvas, self).draw(*args, **kwargs)
-
- def keyPressEvent(self, event):
- event.setAccepted(False)
- super(MplCanvas, self).keyPressEvent(event)
-
- # FigureCanvasBase methods deprecated in 3.6 - see
- # https://github.com/matplotlib/matplotlib/pull/16931
- # adding replacements here for tests convenience.
-
- if MATPLOTLIB_GE_36:
- def resize_event(self):
- self.callbacks.process('resize_event', ResizeEvent('resize_event', self))
-
- def key_press_event(self, event):
- self.callbacks.process('key_press_event', KeyEvent('key_press_event', self, event))
-
- def key_release_event(self, event):
- self.callbacks.process('key_release_event', KeyEvent('key_release_event', self, event))
-
- def button_press_event(self, *event):
- self.callbacks.process('button_press_event',
- MouseEvent('button_press_event', self, *event))
-
- def button_release_event(self, *event):
- self.callbacks.process('button_release_event',
- MouseEvent('button_release_event', self, *event))
-
- def motion_notify_event(self, *event):
- self.callbacks.process('motion_notify_event',
- MouseEvent('motion_notify_event', self, *event))
-
-
-class MplWidget(QtWidgets.QWidget):
-
- """Widget defined in Qt Designer"""
-
- # signals
- rightDrag = QtCore.Signal(float, float)
- leftDrag = QtCore.Signal(float, float)
-
- def __init__(self, parent=None):
- # initialization of Qt MainWindow widget
- QtWidgets.QWidget.__init__(self, parent)
- # set the canvas to the Matplotlib widget
- self.canvas = MplCanvas()
- # create a vertical box layout
- self.vbl = QtWidgets.QVBoxLayout()
- self.vbl.setContentsMargins(0, 0, 0, 0)
- self.vbl.setSpacing(0)
- # add mpl widget to the vertical box
- self.vbl.addWidget(self.canvas)
- # set the layout to the vertical box
- self.setLayout(self.vbl)
-
- self.canvas.rightDrag.connect(self.rightDrag)
- self.canvas.leftDrag.connect(self.leftDrag)
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.matplotlib.qt.widget is deprecated, use glue_qt.viewers.matplotlib.widget instead', GlueDeprecationWarning)
+from glue_qt.viewers.matplotlib.widget import * # noqa
diff --git a/glue/viewers/profile/qt/__init__.py b/glue/viewers/profile/qt/__init__.py
index b1a0a4df1..2b9e5fa54 100644
--- a/glue/viewers/profile/qt/__init__.py
+++ b/glue/viewers/profile/qt/__init__.py
@@ -1,6 +1,4 @@
-from .data_viewer import ProfileViewer # noqa
-
-
-def setup():
- from glue.config import qt_client
- qt_client.add(ProfileViewer)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.profile.qt is deprecated, use glue_qt.viewers.profile instead', GlueDeprecationWarning)
+from glue_qt.viewers.profile import * # noqa
diff --git a/glue/viewers/profile/qt/data_viewer.py b/glue/viewers/profile/qt/data_viewer.py
index 38def7c94..77ed871f7 100644
--- a/glue/viewers/profile/qt/data_viewer.py
+++ b/glue/viewers/profile/qt/data_viewer.py
@@ -1,33 +1,4 @@
-from glue.utils import defer_draw, decorate_all_methods
-
-from glue.viewers.matplotlib.qt.data_viewer import MatplotlibDataViewer
-from glue.viewers.profile.qt.layer_style_editor import ProfileLayerStyleEditor
-from glue.viewers.profile.qt.layer_artist import QThreadedProfileLayerArtist
-from glue.viewers.profile.qt.options_widget import ProfileOptionsWidget
-from glue.viewers.profile.state import ProfileViewerState
-
-from glue.viewers.profile.qt.profile_tools import ProfileAnalysisTool # noqa
-from glue.viewers.profile.viewer import MatplotlibProfileMixin
-
-__all__ = ['ProfileViewer']
-
-
-@decorate_all_methods(defer_draw)
-class ProfileViewer(MatplotlibProfileMixin, MatplotlibDataViewer):
-
- LABEL = '1D Profile'
- _layer_style_widget_cls = ProfileLayerStyleEditor
- _state_cls = ProfileViewerState
- _options_cls = ProfileOptionsWidget
- _data_artist_cls = QThreadedProfileLayerArtist
- _subset_artist_cls = QThreadedProfileLayerArtist
-
- large_data_size = 1e8
-
- allow_duplicate_data = True
-
- tools = ['select:xrange', 'profile-analysis']
-
- def __init__(self, session, parent=None, state=None):
- MatplotlibDataViewer.__init__(self, session, parent=parent, state=state)
- MatplotlibProfileMixin.setup_callbacks(self)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.profile.qt.data_viewer is deprecated, use glue_qt.viewers.profile.data_viewer instead', GlueDeprecationWarning)
+from glue_qt.viewers.profile.data_viewer import * # noqa
diff --git a/glue/viewers/profile/qt/layer_artist.py b/glue/viewers/profile/qt/layer_artist.py
index bcb5e7a97..f584c22fd 100644
--- a/glue/viewers/profile/qt/layer_artist.py
+++ b/glue/viewers/profile/qt/layer_artist.py
@@ -1,62 +1,4 @@
-import time
-
-from glue.viewers.profile.layer_artist import ProfileLayerArtist
-from glue.viewers.matplotlib.qt.compute_worker import ComputeWorker
-from glue.utils import defer_draw
-
-__all__ = ['QThreadedProfileLayerArtist']
-
-
-class QThreadedProfileLayerArtist(ProfileLayerArtist):
-
- def __init__(self, axes, viewer_state, layer_state=None, layer=None):
-
- super(QThreadedProfileLayerArtist, self).__init__(axes, viewer_state,
- layer_state=layer_state, layer=layer)
-
- self.setup_thread()
-
- def wait(self):
- # Wait 0.5 seconds to make sure that the computation has properly started
- time.sleep(0.5)
- while self._worker.running:
- time.sleep(1 / 25)
- from glue.utils.qt import process_events
- process_events()
-
- def remove(self):
- super(QThreadedProfileLayerArtist, self).remove()
- if self._worker is not None:
- self._worker.work_queue.put('stop')
- self._worker.exit()
- # Need to wait otherwise the thread will be destroyed while still
- # running, causing a segmentation fault
- self._worker.wait()
- self._worker = None
-
- @property
- def is_computing(self):
- return self._worker is not None and self._worker.running
-
- def setup_thread(self):
- self._worker = ComputeWorker(self._calculate_profile_thread)
- self._worker.compute_end.connect(self._calculate_profile_postthread)
- self._worker.compute_error.connect(self._calculate_profile_error)
- self._worker.compute_start.connect(self.notify_start_computation)
- self._worker.start()
-
- @defer_draw
- def _calculate_profile(self, reset=False):
- if self.state.layer is not None and self.state.layer.size > 1e7:
- self._worker.work_queue.put(reset)
- else:
- super(QThreadedProfileLayerArtist, self)._calculate_profile(reset=reset)
-
- def _calculate_profile_postthread(self):
-
- # If the worker has started running again, we should stop at this point
- # since this function will get called again.
- if self._worker is not None and self._worker.running:
- return
-
- super(QThreadedProfileLayerArtist, self)._calculate_profile_postthread()
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.profile.qt.layer_artist is deprecated, use glue_qt.viewers.profile.layer_artist instead', GlueDeprecationWarning)
+from glue_qt.viewers.profile.layer_artist import * # noqa
diff --git a/glue/viewers/profile/qt/layer_style_editor.py b/glue/viewers/profile/qt/layer_style_editor.py
index 1d85c11ea..8ff0884bb 100644
--- a/glue/viewers/profile/qt/layer_style_editor.py
+++ b/glue/viewers/profile/qt/layer_style_editor.py
@@ -1,30 +1,4 @@
-import os
-
-from qtpy import QtWidgets
-
-from echo.qt import autoconnect_callbacks_to_qt
-from glue.utils.qt import load_ui
-
-
-class ProfileLayerStyleEditor(QtWidgets.QWidget):
-
- def __init__(self, layer, parent=None):
-
- super(ProfileLayerStyleEditor, self).__init__(parent=parent)
-
- self.ui = load_ui('layer_style_editor.ui', self,
- directory=os.path.dirname(__file__))
-
- connect_kwargs = {'alpha': dict(value_range=(0, 1))}
-
- self._connections = autoconnect_callbacks_to_qt(layer.state, self.ui, connect_kwargs)
-
- self.viewer_state = layer.state.viewer_state
- self.viewer_state.add_callback('normalize', self._on_normalize_change)
- self._on_normalize_change()
-
- def _on_normalize_change(self, *event):
- self.ui.label_limits.setVisible(self.viewer_state.normalize)
- self.ui.valuetext_v_min.setVisible(self.viewer_state.normalize)
- self.ui.valuetext_v_max.setVisible(self.viewer_state.normalize)
- self.ui.button_flip_limits.setVisible(self.viewer_state.normalize)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.profile.qt.layer_style_editor is deprecated, use glue_qt.viewers.profile.layer_style_editor instead', GlueDeprecationWarning)
+from glue_qt.viewers.profile.layer_style_editor import * # noqa
diff --git a/glue/viewers/profile/qt/layer_style_editor.ui b/glue/viewers/profile/qt/layer_style_editor.ui
deleted file mode 100644
index b55fd505e..000000000
--- a/glue/viewers/profile/qt/layer_style_editor.ui
+++ /dev/null
@@ -1,208 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 292
- 150
-
-
-
- Form
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 10
-
-
- 5
-
- -
-
-
-
- 75
- true
-
-
-
- attribute
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- 2
-
-
-
-
-
- -
-
-
- padding: 0px
-
-
- ⇄
-
-
-
- -
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 5
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- color
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- 100
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- opacity
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- linewidth
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- limits
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
-
-
-
-
- QColorBox
- QLabel
-
-
-
-
-
-
diff --git a/glue/viewers/profile/qt/mouse_mode.py b/glue/viewers/profile/qt/mouse_mode.py
index 223f4aa35..7c14a0143 100644
--- a/glue/viewers/profile/qt/mouse_mode.py
+++ b/glue/viewers/profile/qt/mouse_mode.py
@@ -1,194 +1,4 @@
-from echo import CallbackProperty, delay_callback
-from glue.core.state_objects import State
-from glue.viewers.matplotlib.mouse_mode import MouseMode
-
-__all__ = ['NavigateMouseMode', 'RangeMouseMode']
-
-
-COLOR = (0.0, 0.25, 0.7)
-
-
-class NavigationModeState(State):
- x = CallbackProperty(None)
-
-
-class NavigateMouseMode(MouseMode):
-
- def __init__(self, viewer, press_callback=None):
- super(NavigateMouseMode, self).__init__(viewer)
- self.state = NavigationModeState()
- self.state.add_callback('x', self._update_artist)
- self.pressed = False
- self.active = False
- self._press_callback = press_callback
-
- def press(self, event):
- if not self.active or not event.inaxes:
- return
- if self._press_callback is not None:
- self._press_callback()
- self.pressed = True
- self.state.x = event.xdata
-
- def move(self, event):
- if not self.active or not self.pressed or not event.inaxes:
- return
- self.state.x = event.xdata
-
- def release(self, event):
- if not self.active:
- return
- self.pressed = False
-
- def _update_artist(self, *args):
- if hasattr(self, '_line'):
- if self.state.x is None:
- self._line.set_visible(False)
- else:
- self._line.set_visible(True)
- self._line.set_data([self.state.x, self.state.x], [0, 1])
- else:
- if self.state.x is not None:
- self._line = self._axes.axvline(self.state.x, color=COLOR)
- self._canvas.draw_idle()
-
- def deactivate(self):
- if hasattr(self, '_line'):
- self._line.set_visible(False)
- self._canvas.draw_idle()
- super(NavigateMouseMode, self).deactivate()
- self.active = False
-
- def activate(self):
- if hasattr(self, '_line'):
- self._line.set_visible(True)
- self._canvas.draw_idle()
- super(NavigateMouseMode, self).activate()
- self.active = True
-
- def clear(self):
- self.state.x = None
-
-
-class RangeModeState(State):
-
- x_min = CallbackProperty(None)
- x_max = CallbackProperty(None)
-
- @property
- def x_range(self):
- return self.x_min, self.x_max
-
-
-PICK_THRESH = 0.02
-
-
-class RangeMouseMode(MouseMode):
-
- def __init__(self, viewer):
- super(RangeMouseMode, self).__init__(viewer)
- self.state = RangeModeState()
- self.state.add_callback('x_min', self._update_artist)
- self.state.add_callback('x_max', self._update_artist)
- self.pressed = False
-
- self.mode = None
- self.move_params = None
-
- self.active = False
-
- def press(self, event):
-
- if not self.active or not event.inaxes:
- return
-
- self.pressed = True
-
- x_min, x_max = self._axes.get_xlim()
- x_range = abs(x_max - x_min)
-
- if self.state.x_min is None or self.state.x_max is None:
- self.mode = 'move-x-max'
- with delay_callback(self.state, 'x_min', 'x_max'):
- self.state.x_min = event.xdata
- self.state.x_max = event.xdata
- elif abs(event.xdata - self.state.x_min) / x_range < PICK_THRESH:
- self.mode = 'move-x-min'
- elif abs(event.xdata - self.state.x_max) / x_range < PICK_THRESH:
- self.mode = 'move-x-max'
- elif (event.xdata > self.state.x_min) is (event.xdata < self.state.x_max):
- self.mode = 'move'
- self.move_params = (event.xdata, self.state.x_min, self.state.x_max)
- else:
- self.mode = 'move-x-max'
- self.state.x_min = event.xdata
-
- def move(self, event):
-
- if not self.active or not self.pressed or not event.inaxes:
- return
-
- if self.mode == 'move-x-min':
- self.state.x_min = event.xdata
- elif self.mode == 'move-x-max':
- self.state.x_max = event.xdata
- elif self.mode == 'move':
- orig_click, orig_x_min, orig_x_max = self.move_params
- with delay_callback(self.state, 'x_min', 'x_max'):
- self.state.x_min = orig_x_min + (event.xdata - orig_click)
- self.state.x_max = orig_x_max + (event.xdata - orig_click)
-
- def release(self, event):
- if not self.active:
- return
- self.pressed = False
- self.mode = None
- self.move_params
-
- def _update_artist(self, *args):
- y_min, y_max = self._axes.get_ylim()
- if hasattr(self, '_lines'):
- if self.state.x_min is None or self.state.x_max is None:
- self._lines[0].set_visible(False)
- self._lines[1].set_visible(False)
- self._interval.set_visible(False)
- else:
- self._lines[0].set_data([self.state.x_min, self.state.x_min], [0, 1])
- self._lines[1].set_data([self.state.x_max, self.state.x_max], [0, 1])
- self._interval.set_xy([[self.state.x_min, 0],
- [self.state.x_min, 1],
- [self.state.x_max, 1],
- [self.state.x_max, 0],
- [self.state.x_min, 0]])
- else:
- if self.state.x_min is not None and self.state.x_max is not None:
- self._lines = (self._axes.axvline(self.state.x_min, color=COLOR),
- self._axes.axvline(self.state.x_max, color=COLOR))
- self._interval = self._axes.axvspan(self.state.x_min,
- self.state.x_max,
- color=COLOR, alpha=0.05)
- self._canvas.draw_idle()
-
- def deactivate(self):
- if hasattr(self, '_lines'):
- self._lines[0].set_visible(False)
- self._lines[1].set_visible(False)
- self._interval.set_visible(False)
-
- self._canvas.draw_idle()
- super(RangeMouseMode, self).deactivate()
- self.active = False
-
- def activate(self):
- if hasattr(self, '_lines'):
- self._lines[0].set_visible(True)
- self._lines[1].set_visible(True)
- self._interval.set_visible(True)
- self._canvas.draw_idle()
- super(RangeMouseMode, self).activate()
- self.active = True
-
- def clear(self):
- with delay_callback(self.state, 'x_min', 'x_max'):
- self.state.x_min = None
- self.state.x_max = None
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.profile.qt.mouse_mode is deprecated, use glue_qt.viewers.profile.mouse_mode instead', GlueDeprecationWarning)
+from glue_qt.viewers.profile.mouse_mode import * # noqa
diff --git a/glue/viewers/profile/qt/options_widget.py b/glue/viewers/profile/qt/options_widget.py
index 261f16cf3..93ff9ed25 100644
--- a/glue/viewers/profile/qt/options_widget.py
+++ b/glue/viewers/profile/qt/options_widget.py
@@ -1,56 +1,4 @@
-import os
-
-from qtpy import QtWidgets
-
-from glue.core.coordinate_helpers import dependent_axes
-from echo.qt import autoconnect_callbacks_to_qt
-from glue.utils.qt import load_ui, fix_tab_widget_fontsize
-
-__all__ = ['ProfileOptionsWidget']
-
-
-WARNING_TEXT = ("Warning: the coordinate '{label}' is not aligned with pixel "
- "grid, so the values shown on the x-axis are approximate.")
-
-
-class ProfileOptionsWidget(QtWidgets.QWidget):
-
- def __init__(self, viewer_state, session, parent=None):
-
- super(ProfileOptionsWidget, self).__init__(parent=parent)
-
- self.ui = load_ui('options_widget.ui', self,
- directory=os.path.dirname(__file__))
-
- fix_tab_widget_fontsize(self.ui.tab_widget)
-
- self._connections = autoconnect_callbacks_to_qt(viewer_state, self.ui)
- self._connections_axes = autoconnect_callbacks_to_qt(viewer_state, self.ui.axes_editor.ui)
- connect_kwargs = {'alpha': dict(value_range=(0, 1))}
- self._connections_legend = autoconnect_callbacks_to_qt(viewer_state.legend, self.ui.legend_editor.ui, connect_kwargs)
-
- self.viewer_state = viewer_state
-
- self.session = session
-
- self.viewer_state.add_callback('x_att', self._on_attribute_change)
-
- self.ui.text_warning.hide()
-
- def _on_attribute_change(self, *args):
-
- if (self.viewer_state.reference_data is None or
- self.viewer_state.x_att_pixel is None or
- self.viewer_state.x_att is self.viewer_state.x_att_pixel):
- self.ui.text_warning.hide()
- return
-
- world_warning = len(dependent_axes(self.viewer_state.reference_data.coords,
- self.viewer_state.x_att_pixel.axis)) > 1
-
- if world_warning:
- self.ui.text_warning.show()
- self.ui.text_warning.setText(WARNING_TEXT.format(label=self.viewer_state.x_att.label))
- else:
- self.ui.text_warning.hide()
- self.ui.text_warning.setText('')
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.profile.qt.options_widget is deprecated, use glue_qt.viewers.profile.options_widget instead', GlueDeprecationWarning)
+from glue_qt.viewers.profile.options_widget import * # noqa
diff --git a/glue/viewers/profile/qt/options_widget.ui b/glue/viewers/profile/qt/options_widget.ui
deleted file mode 100644
index b46fa5967..000000000
--- a/glue/viewers/profile/qt/options_widget.ui
+++ /dev/null
@@ -1,423 +0,0 @@
-
-
- Widget
-
-
-
- 0
- 0
- 293
- 418
-
-
-
- 1D Profile
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
- 0
-
-
-
- General
-
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 5
-
-
-
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- function
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- x axis
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 5
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- normalize
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
- color: rgb(255, 33, 28)
-
-
- Warning
-
-
- Qt::AlignCenter
-
-
- true
-
-
-
- -
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- reference
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- x unit
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- y_unit
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -
-
-
-
-
-
-
- Limits
-
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 5
-
- -
-
-
- padding: 0px
-
-
- ⇄
-
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
-
- 75
- true
-
-
-
- x axis
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- y axis
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 5
-
-
-
-
- -
-
-
- log
-
-
- true
-
-
-
- -
-
-
- log
-
-
- true
-
-
-
-
- bool_x_log
- valuetext_x_max
- button_flip_x
- valuetext_x_min
- valuetext_y_min
- valuetext_y_max
- bool_y_log
- label_2
- label_5
- verticalSpacer
- horizontalSpacer_2
-
-
-
- Axes
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
-
-
-
-
- Legend
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
-
-
-
-
-
-
-
-
-
- AxesEditorWidget
- QWidget
- glue.viewers.matplotlib.qt.axes_editor
-
-
- LegendEditorWidget
- QWidget
- glue.viewers.matplotlib.qt.legend_editor
-
-
-
-
-
diff --git a/glue/viewers/profile/qt/profile_tools.py b/glue/viewers/profile/qt/profile_tools.py
index 59dd2a7bb..41eb0cf45 100644
--- a/glue/viewers/profile/qt/profile_tools.py
+++ b/glue/viewers/profile/qt/profile_tools.py
@@ -1,354 +1,4 @@
-import os
-import weakref
-import traceback
-from collections import OrderedDict
-
-import numpy as np
-
-from qtpy.QtCore import Qt
-from qtpy import QtWidgets, QtGui
-
-from glue.utils import color2hex
-from glue.config import fit_plugin, viewer_tool
-from glue.utils.qt import load_ui, fix_tab_widget_fontsize
-from glue.viewers.profile.qt.mouse_mode import NavigateMouseMode, RangeMouseMode
-from glue.core.qt.fitters import FitSettingsWidget
-from glue.utils.qt import Worker
-from glue.viewers.common.tool import Tool
-from glue.viewers.image.state import AggregateSlice
-from glue.core.aggregate import mom1, mom2
-from glue.core import BaseData, Subset
-from glue.viewers.image.qt import ImageViewer
-from glue.core.link_manager import is_convertible_to_single_pixel_cid
-from echo import SelectionCallbackProperty
-from echo.qt import connect_combo_selection
-
-__all__ = ['ProfileTools']
-
-
-MODES = ['navigate', 'fit', 'collapse']
-
-COLLAPSE_FUNCS = OrderedDict([(np.nanmean, 'Mean'),
- (np.nanmedian, 'Median'),
- (np.nanmin, 'Minimum'),
- (np.nanmax, 'Maximum'),
- (np.nansum, 'Sum'),
- (mom1, 'Moment 1'),
- (mom2, 'Moment 2')])
-
-
-@viewer_tool
-class ProfileAnalysisTool(Tool):
-
- action_text = 'Options'
- tool_id = 'profile-analysis'
-
- def __init__(self, viewer):
- super(ProfileAnalysisTool, self).__init__(viewer)
- self._profile_tools = ProfileTools(viewer)
- container_widget = QtWidgets.QSplitter(Qt.Horizontal)
- plot_widget = viewer.centralWidget()
- container_widget.addWidget(plot_widget)
- container_widget.addWidget(self._profile_tools)
- viewer.setCentralWidget(container_widget)
- self._profile_tools.enable()
- self._profile_tools.hide()
-
- def activate(self):
- if self._profile_tools.isVisible():
- self._profile_tools.hide()
- else:
- self._profile_tools.show()
-
-
-class ProfileTools(QtWidgets.QWidget):
-
- fit_function = SelectionCallbackProperty()
- collapse_function = SelectionCallbackProperty()
-
- def __init__(self, parent=None):
-
- super(ProfileTools, self).__init__(parent=parent)
-
- self._viewer = weakref.ref(parent)
-
- self.ui = load_ui('profile_tools.ui', self,
- directory=os.path.dirname(__file__))
-
- fix_tab_widget_fontsize(self.ui.tabs)
-
- self.image_viewer = None
-
- @property
- def viewer(self):
- return self._viewer()
-
- def show(self, *args):
- super(ProfileTools, self).show(*args)
- self._on_tab_change()
-
- def hide(self, *args):
- super(ProfileTools, self).hide(*args)
- self.rng_mode.deactivate()
- self.nav_mode.deactivate()
-
- def enable(self):
-
- self.nav_mode = NavigateMouseMode(self.viewer,
- press_callback=self._on_nav_activate)
- self.rng_mode = RangeMouseMode(self.viewer)
-
- self.nav_mode.state.add_callback('x', self._on_slider_change)
-
- self.ui.tabs.setCurrentIndex(0)
-
- self.ui.tabs.currentChanged.connect(self._on_tab_change)
-
- self.ui.button_settings.clicked.connect(self._on_settings)
- self.ui.button_fit.clicked.connect(self._on_fit)
- self.ui.button_clear.clicked.connect(self._on_clear)
- self.ui.button_collapse.clicked.connect(self._on_collapse)
-
- font = QtGui.QFont("Courier")
- font.setStyleHint(font.Monospace)
- self.ui.text_log.document().setDefaultFont(font)
- self.ui.text_log.setLineWrapMode(self.ui.text_log.NoWrap)
-
- self.axes = self.viewer.axes
- self.canvas = self.axes.figure.canvas
-
- self._fit_artists = []
-
- ProfileTools.fit_function.set_choices(self, list(fit_plugin))
- ProfileTools.fit_function.set_display_func(self, lambda fitter: fitter.label)
- self._connection_fit = connect_combo_selection(self, 'fit_function', self.ui.combosel_fit_function)
-
- ProfileTools.collapse_function.set_choices(self, list(COLLAPSE_FUNCS))
- ProfileTools.collapse_function.set_display_func(self, COLLAPSE_FUNCS.get)
- self._connection_collapse = connect_combo_selection(self, 'collapse_function', self.ui.combosel_collapse_function)
-
- self._toolbar_connected = False
-
- self.viewer.toolbar_added.connect(self._on_toolbar_added)
-
- self.viewer.state.add_callback('x_att', self._on_x_att_change)
-
- def _on_x_att_change(self, *event):
- self.nav_mode.clear()
- self.rng_mode.clear()
-
- def _on_nav_activate(self, *args):
- self._nav_data = self._visible_data()
- self._nav_viewers = {}
- for data in self._nav_data:
- pix_cid = is_convertible_to_single_pixel_cid(data, self.viewer.state.x_att_pixel)
- self._nav_viewers[data] = self._viewers_with_data_slice(data, pix_cid)
-
- def _on_slider_change(self, *args):
-
- x = self.nav_mode.state.x
-
- if x is None:
- return
-
- for data in self._nav_data:
-
- axis, slc = self._get_axis_and_pixel_slice(data, x)
-
- for viewer in self._nav_viewers[data]:
- slices = list(viewer.state.slices)
- slices[axis] = slc
- viewer.state.slices = tuple(slices)
-
- def _get_axis_and_pixel_slice(self, data, x):
-
- if self.viewer.state.x_att in data.pixel_component_ids:
- axis = self.viewer.state.x_att.axis
- slc = int(round(x))
- else:
- pix_cid = is_convertible_to_single_pixel_cid(data, self.viewer.state.x_att_pixel)
- axis = pix_cid.axis
- axis_view = [0] * data.ndim
- axis_view[pix_cid.axis] = slice(None)
- axis_values = data[self.viewer.state.x_att, axis_view]
- slc = int(np.argmin(np.abs(axis_values - x)))
-
- return axis, slc
-
- def _on_settings(self):
- d = FitSettingsWidget(self.fit_function())
- d.exec_()
-
- def _on_fit(self):
- """
- Fit a model to the data
-
- The fitting happens on a dedicated thread, to keep the UI
- responsive
- """
-
- if self.rng_mode.state.x_min is None or self.rng_mode.state.x_max is None:
- return
-
- x_range = self.rng_mode.state.x_range
- fitter = self.fit_function()
-
- def on_success(result):
- fit_results, x, y = result
- report = ""
- normalize = {}
- for layer_artist in fit_results:
- report += ("{1}"
- "".format(color2hex(layer_artist.state.color),
- layer_artist.layer.label))
- report += "" + fitter.summarize(fit_results[layer_artist], x, y) + "
"
- if self.viewer.state.normalize:
- normalize[layer_artist] = layer_artist.state.normalize_values
- self._report_fit(report)
- self._plot_fit(fitter, fit_results, x, y, normalize)
-
- def on_fail(exc_info):
- exc = '\n'.join(traceback.format_exception(*exc_info))
- self._report_fit("Error during fitting:\n%s" % exc)
-
- def on_done():
- self.ui.button_fit.setText("Fit")
- self.ui.button_fit.setEnabled(True)
- self.canvas.draw_idle()
-
- self.ui.button_fit.setText("Running...")
- self.ui.button_fit.setEnabled(False)
-
- w = Worker(self._fit, fitter, xlim=x_range)
- w.result.connect(on_success)
- w.error.connect(on_fail)
- w.finished.connect(on_done)
-
- self._fit_worker = w # hold onto a reference
- w.start()
-
- def wait_for_fit(self):
- self._fit_worker.wait()
-
- def _report_fit(self, report):
- self.ui.text_log.document().setHtml(report)
-
- def _on_clear(self):
- self.ui.text_log.document().setPlainText('')
- self._clear_fit()
- self.canvas.draw_idle()
-
- def _fit(self, fitter, xlim=None):
-
- # We cycle through all the visible layers and get the plotted data
- # for each one of them.
-
- results = {}
- for layer in self.viewer.layers:
- if layer.enabled and layer.visible:
- x, y = layer.state.profile
- x = np.asarray(x)
- y = np.asarray(y)
- keep = (x >= min(xlim)) & (x <= max(xlim))
- if len(x) > 0:
- results[layer] = fitter.build_and_fit(x[keep], y[keep])
-
- return results, x, y
-
- def _clear_fit(self):
- for artist in self._fit_artists[:]:
- artist.remove()
- self._fit_artists.remove(artist)
-
- def _plot_fit(self, fitter, fit_result, x, y, normalize):
-
- self._clear_fit()
-
- for layer in fit_result:
- # y_model = fitter.predict(fit_result[layer], x)
- self._fit_artists.append(fitter.plot(fit_result[layer], self.axes, x,
- alpha=layer.state.alpha,
- linewidth=layer.state.linewidth * 0.5,
- color=layer.state.color,
- normalize=normalize.get(layer, None))[0])
-
- self.canvas.draw_idle()
-
- def _visible_data(self):
- datasets = set()
- for layer_artist in self.viewer.layers:
- if layer_artist.enabled and layer_artist.visible:
- if isinstance(layer_artist.state.layer, BaseData):
- datasets.add(layer_artist.state.layer)
- elif isinstance(layer_artist.state.layer, Subset):
- datasets.add(layer_artist.state.layer.data)
- return list(datasets)
-
- def _viewers_with_data_slice(self, data, xatt):
-
- if self.viewer.session.application is None:
- return []
-
- viewers = []
- for tab in self.viewer.session.application.viewers:
- for viewer in tab:
- if isinstance(viewer, ImageViewer):
- for layer_artist in viewer._layer_artist_container[data]:
- if layer_artist.enabled and layer_artist.visible:
- if len(viewer.state.slices) >= xatt.axis:
- viewers.append(viewer)
- return viewers
-
- def _on_collapse(self):
-
- if self.rng_mode.state.x_min is None or self.rng_mode.state.x_max is None:
- return
-
- func = self.collapse_function
- x_range = self.rng_mode.state.x_range
-
- for data in self._visible_data():
-
- pix_cid = is_convertible_to_single_pixel_cid(data, self.viewer.state.x_att_pixel)
-
- for viewer in self._viewers_with_data_slice(data, pix_cid):
-
- slices = list(viewer.state.slices)
-
- # TODO: don't need to fetch axis twice
- axis, imin = self._get_axis_and_pixel_slice(data, x_range[0])
- axis, imax = self._get_axis_and_pixel_slice(data, x_range[1])
-
- current_slice = slices[axis]
-
- if isinstance(current_slice, AggregateSlice):
- current_slice = current_slice.center
-
- imin, imax = min(imin, imax), max(imin, imax)
-
- slices[axis] = AggregateSlice(slice(imin, imax),
- current_slice,
- func)
-
- viewer.state.slices = tuple(slices)
-
- @property
- def mode(self):
- return MODES[self.tabs.currentIndex()]
-
- def _on_toolbar_added(self, *event):
- self.viewer.toolbar.tool_activated.connect(self._on_toolbar_activate)
- self.viewer.toolbar.tool_deactivated.connect(self._on_tab_change)
-
- def _on_toolbar_activate(self, *event):
- self.rng_mode.deactivate()
- self.nav_mode.deactivate()
-
- def _on_tab_change(self, *event):
- mode = self.mode
- if mode == 'navigate':
- self.rng_mode.deactivate()
- self.nav_mode.activate()
- else:
- self.rng_mode.activate()
- self.nav_mode.deactivate()
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.profile.qt.profile_tools is deprecated, use glue_qt.viewers.profile.profile_tools instead', GlueDeprecationWarning)
+from glue_qt.viewers.profile.profile_tools import * # noqa
diff --git a/glue/viewers/profile/qt/profile_tools.ui b/glue/viewers/profile/qt/profile_tools.ui
deleted file mode 100644
index 3e3b2a65b..000000000
--- a/glue/viewers/profile/qt/profile_tools.ui
+++ /dev/null
@@ -1,240 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 293
- 254
-
-
-
- Form
-
-
- -
-
-
- 1
-
-
-
- Navigate
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- <html><head/><body><p>To <span style=" font-weight:600;">slide </span>through any cubes in image viewers that show the same data as the one here, drag the handle from side to side.</p><p>Note that modifying the sliders in the image viewers will not change the slider here or in other viewers.</p></body></html>
-
-
- Qt::AlignJustify|Qt::AlignVCenter
-
-
- true
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
- Fit
-
-
- -
-
-
- Click and drag in the profile to define the range over which to fit models to the data.
-
-
- true
-
-
-
- -
-
-
-
-
-
- Function:
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
- Settings
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Fit
-
-
-
- -
-
-
- Clear
-
-
-
-
-
- -
-
-
-
-
-
-
- Collapse
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- Click and drag in the profile to define the range over which to fit models to the data.
-
-
- true
-
-
-
- -
-
-
-
-
-
- Function:
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Collapse
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/glue/viewers/profile/qt/tests/__init__.py b/glue/viewers/profile/qt/tests/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/glue/viewers/profile/qt/tests/data/profile_v1.glu b/glue/viewers/profile/qt/tests/data/profile_v1.glu
deleted file mode 100644
index ea2f33317..000000000
--- a/glue/viewers/profile/qt/tests/data/profile_v1.glu
+++ /dev/null
@@ -1,703 +0,0 @@
-{
- "CallbackList": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ProfileLayerState",
- "ProfileLayerState_0",
- "ProfileLayerState_1"
- ]
- },
- "CallbackList_0": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ProfileLayerState_2",
- "ProfileLayerState_3",
- "ProfileLayerState_4"
- ]
- },
- "CallbackList_1": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ProfileLayerState_5",
- "ProfileLayerState_6",
- "ProfileLayerState_7"
- ]
- },
- "CallbackList_2": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ProfileLayerState_8",
- "ProfileLayerState_9",
- "ProfileLayerState_10"
- ]
- },
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQB2AHsnZGVzY3InOiAnPGY4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsIDQsIDUpLCB9ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAoAAAAAAAAAAAAAAAAAAPA/AAAAAAAAAEAAAAAAAAAIQAAAAAAAABBAAAAAAAAAFEAAAAAAAAAYQAAAAAAAABxAAAAAAAAAIEAAAAAAAAAiQAAAAAAAACRAAAAAAAAAJkAAAAAAAAAoQAAAAAAAACpAAAAAAAAALEAAAAAAAAAuQAAAAAAAADBAAAAAAAAAMUAAAAAAAAAyQAAAAAAAADNAAAAAAAAANEAAAAAAAAA1QAAAAAAAADZAAAAAAAAAN0AAAAAAAAA4QAAAAAAAADlAAAAAAAAAOkAAAAAAAAA7QAAAAAAAADxAAAAAAAAAPUAAAAAAAAA+QAAAAAAAAD9AAAAAAAAAQEAAAAAAAIBAQAAAAAAAAEFAAAAAAACAQUAAAAAAAABCQAAAAAAAgEJAAAAAAAAAQ0AAAAAAAIBDQAAAAAAAAERAAAAAAACAREAAAAAAAABFQAAAAAAAgEVAAAAAAAAARkAAAAAAAIBGQAAAAAAAAEdAAAAAAACAR0AAAAAAAABIQAAAAAAAgEhAAAAAAAAASUAAAAAAAIBJQAAAAAAAAEpAAAAAAACASkAAAAAAAABLQAAAAAAAgEtAAAAAAAAATEAAAAAAAIBMQAAAAAAAAE1AAAAAAACATUA="
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": false
- },
- "CoordinateComponent_1": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 2,
- "world": false
- },
- "CoordinateComponent_2": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "CoordinateComponent_3": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 1,
- "world": true
- },
- "CoordinateComponent_4": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 2,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 4,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "Pixel Axis 0 [z]",
- "Pixel Axis 1 [y]",
- "Pixel Axis 2 [x]",
- "World 0",
- "World 1",
- "World 2",
- "array_0"
- ],
- "components": [
- "CoordinateComponent",
- "CoordinateComponent_0",
- "CoordinateComponent_1",
- "CoordinateComponent_2",
- "CoordinateComponent_3",
- "CoordinateComponent_4",
- "Component"
- ],
- "data": [
- "array"
- ],
- "groups": [
- "Subset 1",
- "Subset 2"
- ],
- "links": [],
- "subset_group_count": 2
- },
- "Pixel Axis 0 [z]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "label": "Pixel Axis 0 [z]"
- },
- "Pixel Axis 1 [y]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 1,
- "label": "Pixel Axis 1 [y]"
- },
- "Pixel Axis 2 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 2,
- "label": "Pixel Axis 2 [x]"
- },
- "ProfileLayerState": {
- "_type": "glue.viewers.profile.state.ProfileLayerState",
- "values": {
- "alpha": 0.8,
- "attribute": "array_0",
- "color": "st__#919191",
- "layer": "array",
- "linewidth": 1,
- "percentile": 100,
- "v_max": 59.0,
- "v_min": 19.0,
- "visible": true,
- "zorder": 1
- }
- },
- "ProfileLayerState_0": {
- "_type": "glue.viewers.profile.state.ProfileLayerState",
- "values": {
- "alpha": 0.5,
- "attribute": "array_0",
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "linewidth": 1,
- "percentile": 100,
- "v_max": 57.0,
- "v_min": 17.0,
- "visible": true,
- "zorder": 2
- }
- },
- "ProfileLayerState_1": {
- "_type": "glue.viewers.profile.state.ProfileLayerState",
- "values": {
- "alpha": 0.5,
- "attribute": "array_0",
- "color": "st__#33a02c",
- "layer": "Subset 2_0",
- "linewidth": 1,
- "percentile": 100,
- "v_max": 58.0,
- "v_min": 18.0,
- "visible": true,
- "zorder": 3
- }
- },
- "ProfileLayerState_10": {
- "_type": "glue.viewers.profile.state.ProfileLayerState",
- "values": {
- "alpha": 0.5,
- "attribute": "array_0",
- "color": "st__#33a02c",
- "layer": "Subset 2_0",
- "linewidth": 1,
- "percentile": 100,
- "v_max": 30.5,
- "v_min": 30.5,
- "visible": false,
- "zorder": 3
- }
- },
- "ProfileLayerState_2": {
- "_type": "glue.viewers.profile.state.ProfileLayerState",
- "values": {
- "alpha": 0.8,
- "attribute": "array_0",
- "color": "st__#919191",
- "layer": "array",
- "linewidth": 1,
- "percentile": 100,
- "v_max": 59.0,
- "v_min": 44.0,
- "visible": true,
- "zorder": 1
- }
- },
- "ProfileLayerState_3": {
- "_type": "glue.viewers.profile.state.ProfileLayerState",
- "values": {
- "alpha": 0.5,
- "attribute": "array_0",
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "linewidth": 1,
- "percentile": 100,
- "v_max": 57.0,
- "v_min": 42.0,
- "visible": false,
- "zorder": 2
- }
- },
- "ProfileLayerState_4": {
- "_type": "glue.viewers.profile.state.ProfileLayerState",
- "values": {
- "alpha": 0.5,
- "attribute": "array_0",
- "color": "st__#33a02c",
- "layer": "Subset 2_0",
- "linewidth": 1,
- "percentile": 100,
- "v_max": 58.0,
- "v_min": 43.0,
- "visible": true,
- "zorder": 3
- }
- },
- "ProfileLayerState_5": {
- "_type": "glue.viewers.profile.state.ProfileLayerState",
- "values": {
- "alpha": 0.8,
- "attribute": "array_0",
- "color": "st__#919191",
- "layer": "array",
- "linewidth": 1,
- "percentile": 100,
- "v_max": 4.0,
- "v_min": 0.0,
- "visible": true,
- "zorder": 1
- }
- },
- "ProfileLayerState_6": {
- "_type": "glue.viewers.profile.state.ProfileLayerState",
- "values": {
- "alpha": 0.5,
- "attribute": "array_0",
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "linewidth": 1,
- "percentile": 100,
- "v_max": 2.0,
- "v_min": 1.0,
- "visible": true,
- "zorder": 2
- }
- },
- "ProfileLayerState_7": {
- "_type": "glue.viewers.profile.state.ProfileLayerState",
- "values": {
- "alpha": 0.5,
- "attribute": "array_0",
- "color": "st__#33a02c",
- "layer": "Subset 2_0",
- "linewidth": 1,
- "percentile": 100,
- "v_max": 3.0,
- "v_min": 3.0,
- "visible": false,
- "zorder": 3
- }
- },
- "ProfileLayerState_8": {
- "_type": "glue.viewers.profile.state.ProfileLayerState",
- "values": {
- "alpha": 0.8,
- "attribute": "array_0",
- "color": "st__#919191",
- "layer": "array",
- "linewidth": 1,
- "percentile": 100,
- "v_max": 31.5,
- "v_min": 27.5,
- "visible": true,
- "zorder": 1
- }
- },
- "ProfileLayerState_9": {
- "_type": "glue.viewers.profile.state.ProfileLayerState",
- "values": {
- "alpha": 0.5,
- "attribute": "array_0",
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "linewidth": 1,
- "percentile": 100,
- "v_max": 29.5,
- "v_min": 28.5,
- "visible": false,
- "zorder": 2
- }
- },
- "ProfileViewer": {
- "_protocol": 1,
- "_type": "glue.viewers.profile.qt.data_viewer.ProfileViewer",
- "layers": [
- {
- "_type": "glue.viewers.profile.layer_artist.ProfileLayerArtist",
- "state": "ProfileLayerState"
- },
- {
- "_type": "glue.viewers.profile.layer_artist.ProfileLayerArtist",
- "state": "ProfileLayerState_0"
- },
- {
- "_type": "glue.viewers.profile.layer_artist.ProfileLayerArtist",
- "state": "ProfileLayerState_1"
- }
- ],
- "pos": [
- 0,
- 0
- ],
- "session": "Session",
- "size": [
- 600,
- 400
- ],
- "state": {
- "values": {
- "aspect": "st__auto",
- "function": "st__maximum",
- "layers": "CallbackList",
- "normalize": false,
- "reference_data": "array",
- "show_axes": true,
- "x_att": "Pixel Axis 0 [z]",
- "x_att_pixel": "Pixel Axis 0 [z]",
- "x_axislabel": "st__Pixel Axis 0 [z]",
- "x_axislabel_size": 10,
- "x_axislabel_weight": "st__normal",
- "x_log": false,
- "x_max": 2.5,
- "x_min": -0.5,
- "x_ticklabel_size": 8,
- "y_axislabel": "st__Data values",
- "y_axislabel_size": 10,
- "y_axislabel_weight": "st__normal",
- "y_log": false,
- "y_max": 63.0,
- "y_min": 13.0,
- "y_ticklabel_size": 8
- }
- }
- },
- "ProfileViewer_0": {
- "_protocol": 1,
- "_type": "glue.viewers.profile.qt.data_viewer.ProfileViewer",
- "layers": [
- {
- "_type": "glue.viewers.profile.layer_artist.ProfileLayerArtist",
- "state": "ProfileLayerState_2"
- },
- {
- "_type": "glue.viewers.profile.layer_artist.ProfileLayerArtist",
- "state": "ProfileLayerState_3"
- },
- {
- "_type": "glue.viewers.profile.layer_artist.ProfileLayerArtist",
- "state": "ProfileLayerState_4"
- }
- ],
- "pos": [
- 600,
- 1
- ],
- "session": "Session",
- "size": [
- 600,
- 400
- ],
- "state": {
- "values": {
- "aspect": "st__auto",
- "function": "st__maximum",
- "layers": "CallbackList_0",
- "normalize": true,
- "reference_data": "array",
- "show_axes": true,
- "x_att": "Pixel Axis 1 [y]",
- "x_att_pixel": "Pixel Axis 1 [y]",
- "x_axislabel": "st__Pixel Axis 1 [y]",
- "x_axislabel_size": 10,
- "x_axislabel_weight": "st__normal",
- "x_log": false,
- "x_max": 3.5,
- "x_min": -0.5,
- "x_ticklabel_size": 8,
- "y_axislabel": "st__Normalized data values",
- "y_axislabel_size": 10,
- "y_axislabel_weight": "st__normal",
- "y_log": false,
- "y_max": 1.1,
- "y_min": -0.1,
- "y_ticklabel_size": 8
- }
- }
- },
- "ProfileViewer_1": {
- "_protocol": 1,
- "_type": "glue.viewers.profile.qt.data_viewer.ProfileViewer",
- "layers": [
- {
- "_type": "glue.viewers.profile.layer_artist.ProfileLayerArtist",
- "state": "ProfileLayerState_5"
- },
- {
- "_type": "glue.viewers.profile.layer_artist.ProfileLayerArtist",
- "state": "ProfileLayerState_6"
- },
- {
- "_type": "glue.viewers.profile.layer_artist.ProfileLayerArtist",
- "state": "ProfileLayerState_7"
- }
- ],
- "pos": [
- 0,
- 400
- ],
- "session": "Session",
- "size": [
- 600,
- 400
- ],
- "state": {
- "values": {
- "aspect": "st__auto",
- "function": "st__minimum",
- "layers": "CallbackList_1",
- "normalize": false,
- "reference_data": "array",
- "show_axes": true,
- "x_att": "Pixel Axis 2 [x]",
- "x_att_pixel": "Pixel Axis 2 [x]",
- "x_axislabel": "st__Pixel Axis 2 [x]",
- "x_axislabel_size": 10,
- "x_axislabel_weight": "st__normal",
- "x_log": false,
- "x_max": 4.5,
- "x_min": -0.5,
- "x_ticklabel_size": 8,
- "y_axislabel": "st__Data values",
- "y_axislabel_size": 10,
- "y_axislabel_weight": "st__normal",
- "y_log": false,
- "y_max": 4.4,
- "y_min": -0.4,
- "y_ticklabel_size": 8
- }
- }
- },
- "ProfileViewer_2": {
- "_protocol": 1,
- "_type": "glue.viewers.profile.qt.data_viewer.ProfileViewer",
- "layers": [
- {
- "_type": "glue.viewers.profile.layer_artist.ProfileLayerArtist",
- "state": "ProfileLayerState_8"
- },
- {
- "_type": "glue.viewers.profile.layer_artist.ProfileLayerArtist",
- "state": "ProfileLayerState_9"
- },
- {
- "_type": "glue.viewers.profile.layer_artist.ProfileLayerArtist",
- "state": "ProfileLayerState_10"
- }
- ],
- "pos": [
- 600,
- 400
- ],
- "session": "Session",
- "size": [
- 600,
- 400
- ],
- "state": {
- "values": {
- "aspect": "st__auto",
- "function": "st__mean",
- "layers": "CallbackList_2",
- "normalize": false,
- "reference_data": "array",
- "show_axes": true,
- "x_att": "Pixel Axis 2 [x]",
- "x_att_pixel": "Pixel Axis 2 [x]",
- "x_axislabel": "st__Pixel Axis 2 [x]",
- "x_axislabel_size": 10,
- "x_axislabel_weight": "st__normal",
- "x_log": false,
- "x_max": 9.5,
- "x_min": -5.5,
- "x_ticklabel_size": 8,
- "y_axislabel": "st__Data values",
- "y_axislabel_size": 10,
- "y_axislabel_weight": "st__normal",
- "y_log": false,
- "y_max": 31.9,
- "y_min": 27.1,
- "y_ticklabel_size": 8
- }
- }
- },
- "RangeSubsetState": {
- "_type": "glue.core.subset.RangeSubsetState",
- "att": "Pixel Axis 2 [x]",
- "hi": 2.2825159914712154,
- "lo": 0.9925373134328361
- },
- "RangeSubsetState_0": {
- "_type": "glue.core.subset.RangeSubsetState",
- "att": "Pixel Axis 2 [x]",
- "hi": 3.2633262260127935,
- "lo": 2.932835820895522
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "Subset 1": {
- "_type": "glue.core.subset_group.SubsetGroup",
- "label": "Subset 1",
- "state": "RangeSubsetState",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 2.5,
- "marker": "o",
- "markersize": 7
- },
- "subsets": [
- "Subset 1_0"
- ]
- },
- "Subset 1_0": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 1",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 2.5,
- "marker": "o",
- "markersize": 7
- }
- },
- "Subset 2": {
- "_type": "glue.core.subset_group.SubsetGroup",
- "label": "Subset 2",
- "state": "RangeSubsetState_0",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#33a02c",
- "linestyle": "solid",
- "linewidth": 2.5,
- "marker": "o",
- "markersize": 7
- },
- "subsets": [
- "Subset 2_0"
- ]
- },
- "Subset 2_0": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 2",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#33a02c",
- "linestyle": "solid",
- "linewidth": 2.5,
- "marker": "o",
- "markersize": 7
- }
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "World 0"
- },
- "World 1": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "World 1"
- },
- "World 2": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "World 2"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue_plotly",
- "glue.plugins.export_d3po",
- "glue.plugins.tools",
- "glue_vispy_viewers.scatter",
- "glue.plugins.wcs_autolinking",
- "glue.viewers.image.qt",
- "glue.viewers.scatter.qt",
- "glue.viewers.profile.qt",
- "glue.io.formats.fits",
- "glue.plugins.tools.pv_slicer",
- "glue.plugins.dendro_viewer.qt",
- "glue.core.data_exporters",
- "glue.viewers.table.qt",
- "glue.viewers.histogram.qt",
- "glue.plugins.coordinate_helpers",
- "glue_vispy_viewers.volume",
- "glue.plugins.data_factories.spectral_cube"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- [
- "ProfileViewer",
- "ProfileViewer_0",
- "ProfileViewer_1",
- "ProfileViewer_2"
- ]
- ]
- },
- "array": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "Pixel Axis 0 [z]",
- "CoordinateComponent"
- ],
- [
- "Pixel Axis 1 [y]",
- "CoordinateComponent_0"
- ],
- [
- "Pixel Axis 2 [x]",
- "CoordinateComponent_1"
- ],
- [
- "World 0",
- "CoordinateComponent_2"
- ],
- [
- "World 1",
- "CoordinateComponent_3"
- ],
- [
- "World 2",
- "CoordinateComponent_4"
- ],
- [
- "array_0",
- "Component"
- ]
- ],
- "coords": "Coordinates",
- "label": "array",
- "meta": {
- "_type": "collections.OrderedDict",
- "contents": {}
- },
- "primary_owner": [
- "Pixel Axis 0 [z]",
- "Pixel Axis 1 [y]",
- "Pixel Axis 2 [x]",
- "World 0",
- "World 1",
- "World 2",
- "array_0"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "#919191",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [
- "Subset 1_0",
- "Subset 2_0"
- ],
- "uuid": "bcc66633-1537-48a3-8710-96e303bf6a6e"
- },
- "array_0": {
- "_type": "glue.core.component_id.ComponentID",
- "label": "array"
- }
-}
\ No newline at end of file
diff --git a/glue/viewers/profile/qt/tests/test_data_viewer.py b/glue/viewers/profile/qt/tests/test_data_viewer.py
deleted file mode 100644
index c17446a99..000000000
--- a/glue/viewers/profile/qt/tests/test_data_viewer.py
+++ /dev/null
@@ -1,554 +0,0 @@
-# pylint: disable=I0011,W0613,W0201,W0212,E1101,E1103
-
-import os
-
-import pytest
-import numpy as np
-
-from astropy import units as u
-from astropy.wcs import WCS
-
-from numpy.testing import assert_equal, assert_allclose
-
-from glue.core import Data
-from glue.core.roi import XRangeROI
-from glue.core.subset import SliceSubsetState
-from glue.app.qt import GlueApplication
-from glue.core.component_link import ComponentLink
-from glue.viewers.matplotlib.qt.tests.test_data_viewer import BaseTestMatplotlibDataViewer
-from glue.core.coordinates import IdentityCoordinates
-from glue.viewers.profile.tests.test_state import SimpleCoordinates
-from glue.core.tests.test_state import clone
-from glue.core.state import GlueUnSerializer
-from glue.plugins.wcs_autolinking.wcs_autolinking import WCSLink
-from glue.config import settings, unit_converter
-
-from ..data_viewer import ProfileViewer
-
-DATA = os.path.join(os.path.dirname(__file__), 'data')
-
-
-def setup_function(func):
- func.ORIGINAL_UNIT_CONVERTER = settings.UNIT_CONVERTER
-
-
-def teardown_function(func):
- settings.UNIT_CONVERTER = func.ORIGINAL_UNIT_CONVERTER
-
-
-def teardown_module():
- unit_converter._members.pop('test-spectral2')
-
-
-class TestProfileCommon(BaseTestMatplotlibDataViewer):
-
- def init_data(self):
- return Data(label='d1',
- x=np.random.random(24).reshape((3, 4, 2)))
-
- viewer_cls = ProfileViewer
-
- @pytest.mark.skip()
- def test_double_add_ignored(self):
- pass
-
-
-class TestProfileViewer(object):
-
- def setup_method(self, method):
-
- self.data = Data(label='d1')
- self.data.coords = SimpleCoordinates()
- self.data['x'] = np.arange(24).reshape((3, 4, 2))
-
- self.data2 = Data(label='d2')
- self.data2['y'] = np.arange(24).reshape((3, 4, 2))
-
- self.app = GlueApplication()
- self.session = self.app.session
- self.hub = self.session.hub
-
- self.data_collection = self.session.data_collection
- self.data_collection.append(self.data)
- self.data_collection.append(self.data2)
-
- self.viewer = self.app.new_data_viewer(ProfileViewer)
-
- def teardown_method(self, method):
- self.viewer.close()
- self.viewer = None
- self.app.close()
- self.app = None
-
- def test_functions(self):
- self.viewer.add_data(self.data)
- self.viewer.state.function = 'mean'
- assert len(self.viewer.layers) == 1
- layer_artist = self.viewer.layers[0]
- assert_allclose(layer_artist.state.profile[0], [0, 2, 4])
- assert_allclose(layer_artist.state.profile[1], [3.5, 11.5, 19.5])
-
- def test_incompatible(self):
- self.viewer.add_data(self.data)
- data2 = Data(y=np.random.random((3, 4, 2)))
- self.data_collection.append(data2)
- self.viewer.add_data(data2)
- assert len(self.viewer.layers) == 2
- assert self.viewer.layers[0].enabled
- assert not self.viewer.layers[1].enabled
-
- def test_selection(self):
-
- self.viewer.add_data(self.data)
-
- self.viewer.state.x_att = self.data.pixel_component_ids[0]
-
- roi = XRangeROI(0.9, 2.1)
-
- self.viewer.apply_roi(roi)
-
- assert len(self.data.subsets) == 1
- assert_equal(self.data.subsets[0].to_mask()[:, 0, 0], [0, 1, 1])
-
- self.viewer.state.x_att = self.data.world_component_ids[0]
-
- roi = XRangeROI(1.9, 3.1)
-
- self.viewer.apply_roi(roi)
-
- assert len(self.data.subsets) == 1
- assert_equal(self.data.subsets[0].to_mask()[:, 0, 0], [0, 1, 0])
-
- def test_enabled_layers(self):
-
- data2 = Data(label='d1', y=np.arange(24).reshape((3, 4, 2)),
- coords=IdentityCoordinates(n_dim=3))
- self.data_collection.append(data2)
-
- self.viewer.add_data(self.data)
- self.viewer.add_data(data2)
-
- assert self.viewer.layers[0].enabled
- assert not self.viewer.layers[1].enabled
-
- self.data_collection.add_link(ComponentLink([data2.world_component_ids[1]], self.data.world_component_ids[0], using=lambda x: 2 * x))
-
- assert self.viewer.layers[0].enabled
- assert self.viewer.layers[1].enabled
-
- def test_slice_subset_state(self):
-
- self.viewer.add_data(self.data)
-
- subset = self.data.new_subset()
- subset.subset_state = SliceSubsetState(self.data, [slice(1, 2), slice(None)])
-
- assert self.viewer.layers[0].enabled
- assert self.viewer.layers[1].enabled
-
- def test_clone(self):
-
- # Regression test for a bug that meant that deserializing a profile
- # viewer resulted in disabled layers
-
- self.viewer.add_data(self.data)
-
- subset = self.data.new_subset()
- subset.subset_state = SliceSubsetState(self.data, [slice(1, 2), slice(None)])
-
- app = clone(self.app)
-
- assert app.viewers[0][0].layers[0].enabled
- assert app.viewers[0][0].layers[1].enabled
-
- app.close()
-
- def test_incompatible_on_add(self):
-
- # Regression test for a bug when adding a dataset to a profile viewer
- # with a single incompatible subset.
-
- subset_state = SliceSubsetState(self.data, [slice(1, 2), slice(None)])
- self.data_collection.new_subset_group(subset_state=subset_state, label='s1')
-
- data2 = Data(x=[[2, 3], [4, 3]], label='d2')
- self.data_collection.append(data2)
- self.viewer.add_data(data2)
-
- def test_dependent_axes(self):
-
- # Make sure that if we pick a world component that has correlations with
- # others and is not lined up with the pixel grid, a warning is shown.
-
- self.viewer.add_data(self.data)
-
- self.viewer.state.x_att = self.data.pixel_component_ids[0]
- assert self.viewer.options_widget().ui.text_warning.text() == ''
-
- self.viewer.state.x_att = self.data.pixel_component_ids[1]
- assert self.viewer.options_widget().ui.text_warning.text() == ''
-
- self.viewer.state.x_att = self.data.pixel_component_ids[2]
- assert self.viewer.options_widget().ui.text_warning.text() == ''
-
- self.viewer.state.x_att = self.data.world_component_ids[0]
- assert self.viewer.options_widget().ui.text_warning.text() == ''
-
- self.viewer.state.x_att = self.data.world_component_ids[1]
- assert self.viewer.options_widget().ui.text_warning.text() != ''
-
- self.viewer.state.x_att = self.data.world_component_ids[2]
- assert self.viewer.options_widget().ui.text_warning.text() != ''
-
- def test_multiple_data(self, tmpdir):
-
- # Regression test for issues when multiple datasets are present
- # and the reference data is not the default one.
-
- self.viewer.add_data(self.data)
- self.viewer.add_data(self.data2)
- assert self.viewer.layers[0].enabled
- assert not self.viewer.layers[1].enabled
-
- # Make sure that when changing the reference data, which layer
- # is enabled changes.
- self.viewer.state.reference_data = self.data2
- assert not self.viewer.layers[0].enabled
- assert self.viewer.layers[1].enabled
-
- # Make sure that everything works fine after saving/reloading
- filename = tmpdir.join('test_multiple_data.glu').strpath
- self.session.application.save_session(filename)
- with open(filename, 'r') as f:
- session = f.read()
- state = GlueUnSerializer.loads(session)
- ga = state.object('__main__')
- viewer = ga.viewers[0][0]
- assert not viewer.layers[0].enabled
- assert viewer.layers[1].enabled
- ga.close()
-
- @pytest.mark.parametrize('protocol', [1])
- def test_session_back_compat(self, protocol):
-
- filename = os.path.join(DATA, 'profile_v{0}.glu'.format(protocol))
-
- with open(filename, 'r') as f:
- session = f.read()
-
- state = GlueUnSerializer.loads(session)
-
- ga = state.object('__main__')
-
- dc = ga.session.data_collection
-
- assert len(dc) == 1
-
- assert dc[0].label == 'array'
-
- viewer1 = ga.viewers[0][0]
- assert len(viewer1.state.layers) == 3
- assert viewer1.state.x_att_pixel is dc[0].pixel_component_ids[0]
- assert_allclose(viewer1.state.x_min, -0.5)
- assert_allclose(viewer1.state.x_max, 2.5)
- assert_allclose(viewer1.state.y_min, 13)
- assert_allclose(viewer1.state.y_max, 63)
- assert viewer1.state.function == 'maximum'
- assert not viewer1.state.normalize
- assert viewer1.state.layers[0].visible
- assert viewer1.state.layers[1].visible
- assert viewer1.state.layers[2].visible
-
- viewer2 = ga.viewers[0][1]
- assert viewer2.state.x_att_pixel is dc[0].pixel_component_ids[1]
- assert_allclose(viewer2.state.x_min, -0.5)
- assert_allclose(viewer2.state.x_max, 3.5)
- assert_allclose(viewer2.state.y_min, -0.1)
- assert_allclose(viewer2.state.y_max, 1.1)
- assert viewer2.state.function == 'maximum'
- assert viewer2.state.normalize
- assert viewer2.state.layers[0].visible
- assert not viewer2.state.layers[1].visible
- assert viewer2.state.layers[2].visible
-
- viewer3 = ga.viewers[0][2]
- assert viewer3.state.x_att_pixel is dc[0].pixel_component_ids[2]
- assert_allclose(viewer3.state.x_min, -0.5)
- assert_allclose(viewer3.state.x_max, 4.5)
- assert_allclose(viewer3.state.y_min, -0.4)
- assert_allclose(viewer3.state.y_max, 4.4)
- assert viewer3.state.function == 'minimum'
- assert not viewer3.state.normalize
- assert viewer3.state.layers[0].visible
- assert viewer3.state.layers[1].visible
- assert not viewer3.state.layers[2].visible
-
- viewer4 = ga.viewers[0][3]
- assert viewer4.state.x_att_pixel is dc[0].pixel_component_ids[2]
- assert_allclose(viewer4.state.x_min, -5.5)
- assert_allclose(viewer4.state.x_max, 9.5)
- assert_allclose(viewer4.state.y_min, 27.1)
- assert_allclose(viewer4.state.y_max, 31.9)
- assert viewer4.state.function == 'mean'
- assert not viewer4.state.normalize
- assert viewer4.state.layers[0].visible
- assert not viewer4.state.layers[1].visible
- assert not viewer4.state.layers[2].visible
-
- ga.close()
-
- def test_reset_limits(self):
- self.viewer.add_data(self.data)
- self.viewer.add_data(self.data2)
- self.viewer.state.x_min = 0.2
- self.viewer.state.x_max = 0.4
- self.viewer.state.y_min = 0.3
- self.viewer.state.y_max = 0.5
- self.viewer.state.reset_limits()
- assert self.viewer.state.x_min == 0
- assert self.viewer.state.x_max == 4
- assert self.viewer.state.y_min == 7
- assert self.viewer.state.y_max == 23
-
- def test_limits_unchanged(self):
- # Make sure the limits don't change if a subset is created or another
- # dataset added - they should only change if the reference data is changed
- self.viewer.add_data(self.data)
- self.viewer.state.x_min = 0.2
- self.viewer.state.x_max = 0.4
- self.viewer.state.y_min = 0.3
- self.viewer.state.y_max = 0.5
- self.viewer.add_data(self.data2)
- assert self.viewer.state.x_min == 0.2
- assert self.viewer.state.x_max == 0.4
- assert self.viewer.state.y_min == 0.3
- assert self.viewer.state.y_max == 0.5
- roi = XRangeROI(0.9, 2.1)
- self.viewer.apply_roi(roi)
- assert self.viewer.state.x_min == 0.2
- assert self.viewer.state.x_max == 0.4
- assert self.viewer.state.y_min == 0.3
- assert self.viewer.state.y_max == 0.5
-
- def test_layer_visibility(self):
- self.viewer.add_data(self.data)
- assert self.viewer.layers[0].mpl_artists[0].get_visible() is True
- self.viewer.state.layers[0].visible = False
- assert self.viewer.layers[0].mpl_artists[0].get_visible() is False
-
-
-@unit_converter('test-spectral2')
-class SpectralUnitConverter:
-
- def equivalent_units(self, data, cid, units):
- return map(str, u.Unit(units).find_equivalent_units(include_prefix_units=True, equivalencies=u.spectral()))
-
- def to_unit(self, data, cid, values, original_units, target_units):
- return (values * u.Unit(original_units)).to_value(target_units, equivalencies=u.spectral())
-
-
-def test_unit_conversion():
-
- settings.UNIT_CONVERTER = 'test-spectral2'
-
- wcs1 = WCS(naxis=1)
- wcs1.wcs.ctype = ['FREQ']
- wcs1.wcs.crval = [1]
- wcs1.wcs.cdelt = [1]
- wcs1.wcs.crpix = [1]
- wcs1.wcs.cunit = ['GHz']
-
- d1 = Data(f1=[1, 2, 3])
- d1.get_component('f1').units = 'Jy'
- d1.coords = wcs1
-
- wcs2 = WCS(naxis=1)
- wcs2.wcs.ctype = ['WAVE']
- wcs2.wcs.crval = [10]
- wcs2.wcs.cdelt = [10]
- wcs2.wcs.crpix = [1]
- wcs2.wcs.cunit = ['cm']
-
- d2 = Data(f2=[2000, 1000, 3000])
- d2.get_component('f2').units = 'mJy'
- d2.coords = wcs2
-
- app = GlueApplication()
- session = app.session
-
- data_collection = session.data_collection
- data_collection.append(d1)
- data_collection.append(d2)
-
- data_collection.add_link(WCSLink(d1, d2))
-
- viewer = app.new_data_viewer(ProfileViewer)
- viewer.add_data(d1)
- viewer.add_data(d2)
-
- assert viewer.layers[0].enabled
- assert viewer.layers[1].enabled
-
- x, y = viewer.state.layers[0].profile
- assert_allclose(x, [1.e9, 2.e9, 3.e9])
- assert_allclose(y, [1, 2, 3])
-
- x, y = viewer.state.layers[1].profile
- assert_allclose(x, 299792458 / np.array([0.1, 0.2, 0.3]))
- assert_allclose(y, [2000, 1000, 3000])
-
- assert viewer.state.x_min == 1.e9
- assert viewer.state.x_max == 3.e9
- assert viewer.state.y_min == 1.
- assert viewer.state.y_max == 3.
-
- # Change the limits to make sure they are always converted
- viewer.state.x_min = 5e8
- viewer.state.x_max = 4e9
- viewer.state.y_min = 0.5
- viewer.state.y_max = 3.5
-
- roi = XRangeROI(1.4e9, 2.1e9)
- viewer.apply_roi(roi)
-
- assert len(d1.subsets) == 1
- assert_equal(d1.subsets[0].to_mask(), [0, 1, 0])
-
- assert len(d2.subsets) == 1
- assert_equal(d2.subsets[0].to_mask(), [0, 1, 0])
-
- viewer.state.x_display_unit = 'GHz'
- viewer.state.y_display_unit = 'mJy'
-
- x, y = viewer.state.layers[0].profile
- assert_allclose(x, [1, 2, 3])
- assert_allclose(y, [1000, 2000, 3000])
-
- x, y = viewer.state.layers[1].profile
- assert_allclose(x, 2.99792458 / np.array([1, 2, 3]))
- assert_allclose(y, [2000, 1000, 3000])
-
- assert viewer.state.x_min == 0.5
- assert viewer.state.x_max == 4.
-
- # Units get reset because they were originally 'native' and 'native' to a
- # specific unit always trigger resetting the limits since different datasets
- # might be converted in different ways.
- assert viewer.state.y_min == 1000.
- assert viewer.state.y_max == 3000.
-
- # Now set the limits explicitly again and make sure in future they are converted
- viewer.state.y_min = 500.
- viewer.state.y_max = 3500.
-
- roi = XRangeROI(0.5, 1.2)
- viewer.apply_roi(roi)
-
- assert len(d1.subsets) == 1
- assert_equal(d1.subsets[0].to_mask(), [1, 0, 0])
-
- assert len(d2.subsets) == 1
- assert_equal(d2.subsets[0].to_mask(), [0, 0, 1])
-
- viewer.state.x_display_unit = 'cm'
- viewer.state.y_display_unit = 'Jy'
-
- roi = XRangeROI(15, 35)
- viewer.apply_roi(roi)
-
- assert len(d1.subsets) == 1
- assert_equal(d1.subsets[0].to_mask(), [1, 0, 0])
-
- assert len(d2.subsets) == 1
- assert_equal(d2.subsets[0].to_mask(), [0, 1, 1])
-
- assert_allclose(viewer.state.x_min, (4 * u.GHz).to_value(u.cm, equivalencies=u.spectral()))
- assert_allclose(viewer.state.x_max, (0.5 * u.GHz).to_value(u.cm, equivalencies=u.spectral()))
- assert_allclose(viewer.state.y_min, 0.5)
- assert_allclose(viewer.state.y_max, 3.5)
-
-
-def test_unit_conversion_limits():
-
- # Regression test for issues that happened when changing attributes with
- # different units.
-
- wcs1 = WCS(naxis=2)
- wcs1.wcs.ctype = ['A', 'B']
- wcs1.wcs.crval = [1, 3]
- wcs1.wcs.cdelt = [1, 2]
- wcs1.wcs.crpix = [1, 1]
- wcs1.wcs.cunit = ['deg', 'm']
-
- d1 = Data(f1=[[1, 2, 3]], f2=[[10, 20, 30]])
- d1.get_component('f1').units = 'Jy'
- d1.get_component('f2').units = 's'
- d1.coords = wcs1
-
- app = GlueApplication()
- session = app.session
-
- data_collection = session.data_collection
- data_collection.append(d1)
-
- viewer = app.new_data_viewer(ProfileViewer)
- viewer.add_data(d1)
-
- assert viewer.state.x_att is d1.id['B']
-
- assert viewer.state.x_min == 3.0
- assert viewer.state.x_max == 3.0
- assert viewer.state.y_min == 0.
- assert viewer.state.y_max == 1.
-
- # Explicitly set unit on y axis to enable unit conversion
- viewer.state.y_display_unit = 'Jy'
-
- assert_allclose(viewer.state.layers[0].profile[0], [3])
- assert_allclose(viewer.state.layers[0].profile[1], [3])
-
- # Change the limits to see if they are updated or reset
- viewer.state.x_min = 0.
- viewer.state.x_max = 10
- viewer.state.y_min = 0.0
- viewer.state.y_max = 4.0
-
- viewer.state.x_display_unit = 'cm'
-
- assert_allclose(viewer.state.layers[0].profile[0], [300])
- assert_allclose(viewer.state.layers[0].profile[1], [3])
-
- assert_allclose(viewer.state.x_min, 0)
- assert_allclose(viewer.state.x_max, 1000)
- assert_allclose(viewer.state.y_min, 0)
- assert_allclose(viewer.state.y_max, 4)
-
- viewer.state.y_display_unit = 'mJy'
-
- assert_allclose(viewer.state.layers[0].profile[0], [300])
- assert_allclose(viewer.state.layers[0].profile[1], [3000])
-
- assert_allclose(viewer.state.x_min, 0)
- assert_allclose(viewer.state.x_max, 1000)
- assert_allclose(viewer.state.y_min, 0)
- assert_allclose(viewer.state.y_max, 4000)
-
- viewer.state.x_att = d1.id['A']
-
- assert_allclose(viewer.state.layers[0].profile[0], [1, 2, 3])
- assert_allclose(viewer.state.layers[0].profile[1], [1000, 2000, 3000])
-
- assert_allclose(viewer.state.x_min, 1)
- assert_allclose(viewer.state.x_max, 3)
- assert_allclose(viewer.state.y_min, 0)
- assert_allclose(viewer.state.y_max, 4000)
-
- viewer.state.layers[0].attribute = d1.id['f2']
-
- assert_allclose(viewer.state.layers[0].profile[0], [1, 2, 3])
- assert_allclose(viewer.state.layers[0].profile[1], [10, 20, 30])
-
- assert_allclose(viewer.state.x_min, 1)
- assert_allclose(viewer.state.x_max, 3)
- assert_allclose(viewer.state.y_min, 10)
- assert_allclose(viewer.state.y_max, 30)
diff --git a/glue/viewers/profile/qt/tests/test_mouse_mode.py b/glue/viewers/profile/qt/tests/test_mouse_mode.py
deleted file mode 100644
index e12c873d6..000000000
--- a/glue/viewers/profile/qt/tests/test_mouse_mode.py
+++ /dev/null
@@ -1,173 +0,0 @@
-from unittest.mock import MagicMock
-
-from matplotlib import pyplot as plt
-
-from ..mouse_mode import NavigateMouseMode, RangeMouseMode
-
-
-def test_navigate_mouse_mode():
-
- callback = MagicMock()
-
- fig = plt.figure()
- ax = fig.add_subplot(1, 1, 1)
- ax.set_xlim(0, 10)
- viewer = MagicMock()
- viewer.axes = ax
- mode = NavigateMouseMode(viewer, press_callback=callback)
-
- event = MagicMock()
- event.xdata = 1.5
- event.inaxes = True
- mode.press(event)
- assert mode.state.x is None
- mode.move(event)
- assert mode.state.x is None
- mode.release(event)
- assert mode.state.x is None
- mode.activate()
- mode.press(event)
- assert callback.call_count == 1
- assert mode.state.x == 1.5
- event.xdata = 2.5
- mode.move(event)
- assert mode.state.x == 2.5
- mode.release(event)
- event.xdata = 3.5
- mode.move(event)
- assert mode.state.x == 2.5
- mode.deactivate()
- event.xdata = 1.5
- mode.press(event)
- assert callback.call_count == 1
- assert mode.state.x == 2.5
- mode.activate()
- event.xdata = 3.5
- mode.press(event)
- assert callback.call_count == 2
- assert mode.state.x == 3.5
- event.inaxes = False
- event.xdata = 4.5
- mode.press(event)
- assert callback.call_count == 2
- assert mode.state.x == 3.5
-
-
-def test_range_mouse_mode():
-
- fig = plt.figure()
- ax = fig.add_subplot(1, 1, 1)
- ax.set_xlim(0, 10)
- viewer = MagicMock()
- viewer.axes = ax
- mode = RangeMouseMode(viewer)
-
- event = MagicMock()
- event.xdata = 1.5
- event.inaxes = True
-
- # Pressing, moving, and releasing doesn't do anything until mode is active
- mode.press(event)
- assert mode.state.x_min is None
- assert mode.state.x_max is None
- mode.move(event)
- assert mode.state.x_min is None
- assert mode.state.x_max is None
- mode.release(event)
- assert mode.state.x_min is None
- assert mode.state.x_max is None
-
- mode.activate()
-
- # Click and drag then creates an interval where x_min is the first value
- # that was clicked and x_max is set to the position of the mouse while
- # dragging and at the point of releasing.
-
- mode.press(event)
- assert mode.state.x_min == 1.5
- assert mode.state.x_max == 1.5
-
- event.xdata = 2.5
- mode.move(event)
- assert mode.state.x_min == 1.5
- assert mode.state.x_max == 2.5
-
- event.xdata = 3.5
- mode.move(event)
- assert mode.state.x_min == 1.5
- assert mode.state.x_max == 3.5
-
- mode.release(event)
- event.xdata = 4.5
- mode.move(event)
- assert mode.state.x_min == 1.5
- assert mode.state.x_max == 3.5
-
- # Test that we can drag the existing edges by clicking on then
-
- event.xdata = 1.49
- mode.press(event)
- event.xdata = 1.25
- mode.move(event)
- assert mode.state.x_min == 1.25
- assert mode.state.x_max == 3.5
- mode.release(event)
-
- event.xdata = 3.51
- mode.press(event)
- event.xdata = 4.0
- mode.move(event)
- assert mode.state.x_min == 1.25
- assert mode.state.x_max == 4.0
- mode.release(event)
-
- # Test that we can drag the entire interval by clicking inside
-
- event.xdata = 2
- mode.press(event)
- event.xdata = 3
- mode.move(event)
- assert mode.state.x_min == 2.25
- assert mode.state.x_max == 5.0
- mode.release(event)
-
- # Test that x_range works
-
- assert mode.state.x_range == (2.25, 5.0)
-
- # Clicking outside the range starts a new interval
-
- event.xdata = 6
- mode.press(event)
- event.xdata = 7
- mode.move(event)
- assert mode.state.x_min == 6
- assert mode.state.x_max == 7
- mode.release(event)
-
- # Deactivate and activate again to make sure that code for hiding/showing
- # artists gets executed
-
- mode.deactivate()
-
- event.xdata = 8
- mode.press(event)
- assert mode.state.x_min == 6
- assert mode.state.x_max == 7
-
- mode.activate()
-
- event.xdata = 9
- mode.press(event)
- event.xdata = 10
- mode.move(event)
- assert mode.state.x_min == 9
- assert mode.state.x_max == 10
-
- # Check that events outside the axes get ignored
-
- event.inaxes = False
- event.xdata = 11
- mode.press(event)
- assert mode.state.x_min == 9
- assert mode.state.x_max == 10
diff --git a/glue/viewers/profile/qt/tests/test_profile_tools.py b/glue/viewers/profile/qt/tests/test_profile_tools.py
deleted file mode 100644
index 3e3e1a5fe..000000000
--- a/glue/viewers/profile/qt/tests/test_profile_tools.py
+++ /dev/null
@@ -1,215 +0,0 @@
-import pytest
-import numpy as np
-
-from numpy.testing import assert_allclose
-
-from glue.core import Data
-from glue.tests.helpers import PYSIDE2_INSTALLED # noqa
-from glue.app.qt import GlueApplication
-from glue.utils.qt import process_events
-from glue.viewers.image.state import AggregateSlice
-
-from glue.viewers.image.qt import ImageViewer
-from glue.viewers.profile.tests.test_state import SimpleCoordinates
-from ..data_viewer import ProfileViewer
-
-
-class TestProfileTools(object):
-
- def setup_method(self, method):
-
- self.data = Data(label='d1')
- self.data.coords = SimpleCoordinates()
- self.data['x'] = np.arange(240).reshape((30, 4, 2)).astype(float)
-
- self.app = GlueApplication()
- self.session = self.app.session
- self.hub = self.session.hub
-
- self.data_collection = self.session.data_collection
- self.data_collection.append(self.data)
-
- self.viewer = self.app.new_data_viewer(ProfileViewer)
- self.viewer.state.function = 'mean'
-
- self.viewer.toolbar.active_tool = 'profile-analysis'
-
- self.profile_tools = self.viewer.toolbar.tools['profile-analysis']._profile_tools
-
- def teardown_method(self, method):
- self.viewer.close()
- self.viewer = None
- self.app.close()
- self.app = None
-
- def test_navigate_sync_image(self):
-
- self.viewer.add_data(self.data)
- image_viewer = self.app.new_data_viewer(ImageViewer)
- image_viewer.add_data(self.data)
- assert image_viewer.state.slices == (0, 0, 0)
-
- self.viewer.state.x_att = self.data.pixel_component_ids[0]
-
- # Force events to be processed to make sure that the callback functions
- # for the computation thread are executed (since they rely on signals)
- self.viewer.layers[0].wait()
- process_events()
-
- x, y = self.viewer.axes.transData.transform([[1, 4]])[0]
- self.viewer.axes.figure.canvas.button_press_event(x, y, 1)
- self.viewer.axes.figure.canvas.button_release_event(x, y, 1)
- assert image_viewer.state.slices == (1, 0, 0)
-
- self.viewer.state.x_att = self.data.world_component_ids[0]
-
- x, y = self.viewer.axes.transData.transform([[10, 4]])[0]
- self.viewer.axes.figure.canvas.button_press_event(x, y, 1)
- self.viewer.axes.figure.canvas.button_release_event(x, y, 1)
- assert image_viewer.state.slices == (5, 0, 0)
-
- @pytest.mark.skipif('PYSIDE2_INSTALLED')
- def test_fit_polynomial(self):
-
- # TODO: need to deterministically set to polynomial fitter
-
- self.viewer.add_data(self.data)
- self.profile_tools.ui.tabs.setCurrentIndex(1)
-
- # First try in pixel coordinates
-
- self.viewer.state.x_att = self.data.pixel_component_ids[0]
-
- # Force events to be processed to make sure that the callback functions
- # for the computation thread are executed (since they rely on signals)
- self.viewer.layers[0].wait()
- process_events()
-
- x, y = self.viewer.axes.transData.transform([[0.9, 4]])[0]
- self.viewer.axes.figure.canvas.button_press_event(x, y, 1)
- x, y = self.viewer.axes.transData.transform([[15.1, 4]])[0]
- self.viewer.axes.figure.canvas.motion_notify_event(x, y, 1)
-
- assert_allclose(self.profile_tools.rng_mode.state.x_range, (0.9, 15.1))
-
- self.profile_tools.ui.button_fit.click()
- self.profile_tools.wait_for_fit()
-
- # Force events to be processed to make sure that the callback functions
- # for the computation thread are executed (since they rely on signals)
- process_events()
-
- pixel_log = self.profile_tools.text_log.toPlainText().splitlines()
- assert pixel_log[0] == 'd1'
- assert pixel_log[1] == 'Coefficients:'
- assert pixel_log[-2] == '8.000000e+00'
- assert pixel_log[-1] == '3.500000e+00'
-
- self.profile_tools.ui.button_clear.click()
- assert self.profile_tools.text_log.toPlainText() == ''
-
- # Next, try in world coordinates
-
- self.viewer.state.x_att = self.data.world_component_ids[0]
-
- x, y = self.viewer.axes.transData.transform([[1.9, 4]])[0]
- self.viewer.axes.figure.canvas.button_press_event(x, y, 1)
- x, y = self.viewer.axes.transData.transform([[30.1, 4]])[0]
- self.viewer.axes.figure.canvas.motion_notify_event(x, y, 1)
-
- assert_allclose(self.profile_tools.rng_mode.state.x_range, (1.9, 30.1))
-
- self.profile_tools.ui.button_fit.click()
- self.profile_tools.wait_for_fit()
- process_events()
-
- world_log = self.profile_tools.text_log.toPlainText().splitlines()
- assert world_log[0] == 'd1'
- assert world_log[1] == 'Coefficients:'
- assert world_log[-2] == '4.000000e+00'
- assert world_log[-1] == '3.500000e+00'
-
- def test_collapse(self):
-
- self.viewer.add_data(self.data)
-
- image_viewer = self.app.new_data_viewer(ImageViewer)
- image_viewer.add_data(self.data)
-
- self.profile_tools.ui.tabs.setCurrentIndex(2)
-
- # First try in pixel coordinates
-
- self.viewer.state.x_att = self.data.pixel_component_ids[0]
-
- # Force events to be processed to make sure that the callback functions
- # for the computation thread are executed (since they rely on signals)
- self.viewer.layers[0].wait()
- process_events()
-
- x, y = self.viewer.axes.transData.transform([[0.9, 4]])[0]
- self.viewer.axes.figure.canvas.button_press_event(x, y, 1)
- x, y = self.viewer.axes.transData.transform([[15.1, 4]])[0]
- self.viewer.axes.figure.canvas.motion_notify_event(x, y, 1)
-
- self.profile_tools.ui.button_collapse.click()
-
- assert isinstance(image_viewer.state.slices[0], AggregateSlice)
- assert image_viewer.state.slices[0].slice.start == 1
- assert image_viewer.state.slices[0].slice.stop == 15
- assert image_viewer.state.slices[0].center == 0
- assert image_viewer.state.slices[0].function is np.nanmean
-
- # Next, try in world coordinates
-
- self.viewer.state.x_att = self.data.world_component_ids[0]
-
- # Force events to be processed to make sure that the callback functions
- # for the computation thread are executed (since they rely on signals)
- self.viewer.layers[0].wait()
- process_events()
-
- x, y = self.viewer.axes.transData.transform([[1.9, 4]])[0]
- self.viewer.axes.figure.canvas.button_press_event(x, y, 1)
- x, y = self.viewer.axes.transData.transform([[30.1, 4]])[0]
- self.viewer.axes.figure.canvas.motion_notify_event(x, y, 1)
-
- self.profile_tools.ui.button_collapse.click()
-
- assert isinstance(image_viewer.state.slices[0], AggregateSlice)
- assert image_viewer.state.slices[0].slice.start == 1
- assert image_viewer.state.slices[0].slice.stop == 15
- assert image_viewer.state.slices[0].center == 0
- assert image_viewer.state.slices[0].function is np.nanmean
-
- def test_collapse_reverse(self, capsys):
-
- # Regression test for a bug that caused collapsing to fail if selecting
- # the range in the reverse direction.
-
- self.viewer.add_data(self.data)
-
- image_viewer = self.app.new_data_viewer(ImageViewer)
- image_viewer.add_data(self.data)
-
- self.profile_tools.ui.tabs.setCurrentIndex(2)
-
- self.viewer.state.x_att = self.data.pixel_component_ids[0]
-
- # Force events to be processed to make sure that the callback functions
- # for the computation thread are executed (since they rely on signals)
- self.viewer.layers[0].wait()
- process_events()
-
- x, y = self.viewer.axes.transData.transform([[15.1, 4]])[0]
- self.viewer.axes.figure.canvas.button_press_event(x, y, 1)
- x, y = self.viewer.axes.transData.transform([[0.9, 4]])[0]
- self.viewer.axes.figure.canvas.motion_notify_event(x, y, 1)
-
- self.profile_tools.ui.button_collapse.click()
- process_events()
-
- # We use capsys here because the # error is otherwise only apparent in stderr.
- out, err = capsys.readouterr()
- assert out.strip() == ""
- assert err.strip() == ""
diff --git a/glue/viewers/profile/qt/tests/test_python_export.py b/glue/viewers/profile/qt/tests/test_python_export.py
deleted file mode 100644
index fa9c3b0c0..000000000
--- a/glue/viewers/profile/qt/tests/test_python_export.py
+++ /dev/null
@@ -1,89 +0,0 @@
-from astropy.utils import NumpyRNGContext
-
-from glue.core import Data, DataCollection
-from glue.app.qt.application import GlueApplication
-from glue.viewers.matplotlib.qt.tests.test_python_export import BaseTestExportPython, random_with_nan
-from glue.viewers.profile.qt import ProfileViewer
-from glue.viewers.profile.tests.test_state import SimpleCoordinates
-
-
-class TestExportPython(BaseTestExportPython):
-
- def setup_method(self, method):
-
- self.data = Data(label='d1')
- self.data.coords = SimpleCoordinates()
- with NumpyRNGContext(12345):
- self.data['x'] = random_with_nan(48, 5).reshape((6, 4, 2))
- self.data['y'] = random_with_nan(48, 12).reshape((6, 4, 2))
- self.data_collection = DataCollection([self.data])
- self.app = GlueApplication(self.data_collection)
- self.viewer = self.app.new_data_viewer(ProfileViewer)
- self.viewer.add_data(self.data)
- # Make legend location deterministic
- self.viewer.state.legend.location = 'lower left'
-
- def teardown_method(self, method):
- self.viewer.close()
- self.viewer = None
- self.app.close()
- self.app = None
-
- def test_simple(self, tmpdir):
- self.assert_same(tmpdir)
-
- def test_simple_legend(self, tmpdir):
- self.viewer.state.legend.visible = True
- self.assert_same(tmpdir)
-
- def test_color(self, tmpdir):
- self.viewer.state.layers[0].color = '#ac0567'
- self.assert_same(tmpdir)
-
- def test_linewidth(self, tmpdir):
- self.viewer.state.layers[0].linewidth = 7.25
- self.assert_same(tmpdir)
-
- def test_max(self, tmpdir):
- self.viewer.state.function = 'maximum'
- self.assert_same(tmpdir)
-
- def test_min(self, tmpdir):
- self.viewer.state.function = 'minimum'
- self.assert_same(tmpdir)
-
- def test_mean(self, tmpdir):
- self.viewer.state.function = 'mean'
- self.assert_same(tmpdir)
-
- def test_median(self, tmpdir):
- self.viewer.state.function = 'median'
- self.assert_same(tmpdir)
-
- def test_sum(self, tmpdir):
- self.viewer.state.function = 'sum'
- self.assert_same(tmpdir)
-
- def test_normalization(self, tmpdir):
- self.viewer.state.normalize = True
- self.assert_same(tmpdir)
-
- def test_subset(self, tmpdir):
- self.viewer.state.function = 'mean'
- self.data_collection.new_subset_group('mysubset', self.data.id['x'] > 0.25)
- self.assert_same(tmpdir)
-
- def test_subset_legend(self, tmpdir):
- self.viewer.state.legend.visible = True
- self.viewer.state.function = 'mean'
- self.viewer.state.layers[0].linewidth = 7.25
- self.data_collection.new_subset_group('mysubset', self.data.id['x'] > 0.25)
- self.assert_same(tmpdir)
-
- def test_xatt(self, tmpdir):
- self.viewer.x_att = self.data.pixel_component_ids[1]
- self.assert_same(tmpdir)
-
- def test_profile_att(self, tmpdir):
- self.viewer.layers[0].state.attribute = self.data.id['y']
- self.assert_same(tmpdir)
diff --git a/glue/viewers/scatter/layer_artist.py b/glue/viewers/scatter/layer_artist.py
index 3c22ccf4a..bb8ac5c6e 100644
--- a/glue/viewers/scatter/layer_artist.py
+++ b/glue/viewers/scatter/layer_artist.py
@@ -6,9 +6,9 @@
from mpl_scatter_density.generic_density_artist import GenericDensityArtist
-from astropy.visualization import (ImageNormalize, LinearStretch, SqrtStretch,
- AsinhStretch, LogStretch)
+from astropy.visualization import ImageNormalize
+from glue.config import stretches
from glue.utils import defer_draw, ensure_numerical, datetime64_to_mpl
from glue.viewers.scatter.state import ScatterLayerState
from glue.viewers.scatter.python_export import python_export_scatter_layer
@@ -17,11 +17,9 @@
from matplotlib.lines import Line2D
-
-STRETCHES = {'linear': LinearStretch,
- 'sqrt': SqrtStretch,
- 'arcsinh': AsinhStretch,
- 'log': LogStretch}
+# We keep the following so that scripts exported with previous versions of glue
+# continue to work, as they imported STRETCHES from here.
+STRETCHES = stretches.members
CMAP_PROPERTIES = set(['cmap_mode', 'cmap_att', 'cmap_vmin', 'cmap_vmax', 'cmap'])
MARKER_PROPERTIES = set(['size_mode', 'size_att', 'size_vmin', 'size_vmax', 'size_scaling', 'size', 'fill'])
@@ -367,7 +365,7 @@ def _update_visual_attributes(self, changed, force=False):
set_mpl_artist_cmap(self.density_artist, c, self.state)
if force or 'stretch' in changed:
- self.density_artist.set_norm(ImageNormalize(stretch=STRETCHES[self.state.stretch]()))
+ self.density_artist.set_norm(ImageNormalize(stretch=stretches.members[self.state.stretch]))
if force or 'dpi' in changed:
self.density_artist.set_dpi(self._viewer_state.dpi)
diff --git a/glue/viewers/scatter/python_export.py b/glue/viewers/scatter/python_export.py
index fcd98287b..717805078 100644
--- a/glue/viewers/scatter/python_export.py
+++ b/glue/viewers/scatter/python_export.py
@@ -77,7 +77,8 @@ def python_export_scatter_layer(layer, *args):
if layer.state.density_map:
imports += ["from mpl_scatter_density import ScatterDensityArtist"]
- imports += ["from glue.viewers.scatter.layer_artist import DensityMapLimits, STRETCHES"]
+ imports += ["from glue.config import stretches"]
+ imports += ["from glue.viewers.scatter.layer_artist import DensityMapLimits"]
imports += ["from astropy.visualization import ImageNormalize"]
script += "density_limits = DensityMapLimits()\n"
@@ -91,7 +92,7 @@ def python_export_scatter_layer(layer, *args):
options['color'] = layer.state.color
options['vmin'] = code('density_limits.min')
options['vmax'] = code('density_limits.max')
- options['norm'] = code("ImageNormalize(stretch=STRETCHES['{0}']())".format(layer.state.stretch))
+ options['norm'] = code("ImageNormalize(stretch=stretches.members['{0}'])".format(layer.state.stretch))
else:
options['c'] = code("layer_data['{0}']".format(layer.state.cmap_att.label))
options['cmap'] = code("plt.cm.{0}".format(layer.state.cmap.name))
diff --git a/glue/viewers/scatter/qt/__init__.py b/glue/viewers/scatter/qt/__init__.py
index 090ca88c5..5c9d59659 100644
--- a/glue/viewers/scatter/qt/__init__.py
+++ b/glue/viewers/scatter/qt/__init__.py
@@ -1,6 +1,4 @@
-from .data_viewer import ScatterViewer # noqa
-
-
-def setup():
- from glue.config import qt_client
- qt_client.add(ScatterViewer)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.scatter.qt is deprecated, use glue_qt.viewers.scatter instead', GlueDeprecationWarning)
+from glue_qt.viewers.scatter import * # noqa
diff --git a/glue/viewers/scatter/qt/data_viewer.py b/glue/viewers/scatter/qt/data_viewer.py
index 9e4d7f6d8..b9f1f1865 100644
--- a/glue/viewers/scatter/qt/data_viewer.py
+++ b/glue/viewers/scatter/qt/data_viewer.py
@@ -1,37 +1,4 @@
-from glue.utils import defer_draw, decorate_all_methods
-from glue.viewers.matplotlib.qt.data_viewer import MatplotlibDataViewer
-from glue.viewers.scatter.qt.layer_style_editor import ScatterLayerStyleEditor
-from glue.viewers.scatter.layer_artist import ScatterLayerArtist
-from glue.viewers.scatter.qt.options_widget import ScatterOptionsWidget
-from glue.viewers.scatter.state import ScatterViewerState
-
-from glue.viewers.scatter.viewer import MatplotlibScatterMixin
-
-
-__all__ = ['ScatterViewer']
-
-
-@decorate_all_methods(defer_draw)
-class ScatterViewer(MatplotlibScatterMixin, MatplotlibDataViewer):
-
- LABEL = '2D Scatter'
- _layer_style_widget_cls = ScatterLayerStyleEditor
- _state_cls = ScatterViewerState
- _options_cls = ScatterOptionsWidget
- _data_artist_cls = ScatterLayerArtist
- _subset_artist_cls = ScatterLayerArtist
-
- tools = ['select:rectangle', 'select:xrange',
- 'select:yrange', 'select:circle',
- 'select:polygon']
-
- def __init__(self, session, parent=None, state=None):
- proj = None if not state or not state.plot_mode else state.plot_mode
- MatplotlibDataViewer.__init__(self, session, parent=parent, state=state, projection=proj)
- MatplotlibScatterMixin.setup_callbacks(self)
-
- def limits_to_mpl(self, *args):
- # These projections throw errors if we try to set the limits
- if self.state.plot_mode in ['aitoff', 'hammer', 'lambert', 'mollweide']:
- return
- super().limits_to_mpl(*args)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.scatter.qt.data_viewer is deprecated, use glue_qt.viewers.scatter.data_viewer instead', GlueDeprecationWarning)
+from glue_qt.viewers.scatter.data_viewer import * # noqa
diff --git a/glue/viewers/scatter/qt/layer_style_editor.py b/glue/viewers/scatter/qt/layer_style_editor.py
index 8c60fe2a7..39c7a490c 100644
--- a/glue/viewers/scatter/qt/layer_style_editor.py
+++ b/glue/viewers/scatter/qt/layer_style_editor.py
@@ -1,228 +1,4 @@
-import os
-
-import numpy as np
-
-from qtpy import QtWidgets, QtGui
-from qtpy.QtCore import Qt
-
-from glue.core import BaseData
-from echo.qt import autoconnect_callbacks_to_qt, connect_value
-from glue.utils.qt import load_ui, fix_tab_widget_fontsize
-from glue.core.exceptions import IncompatibleAttribute
-
-
-class ScatterLayerStyleEditor(QtWidgets.QWidget):
-
- def __init__(self, layer, parent=None):
-
- super(ScatterLayerStyleEditor, self).__init__(parent=parent)
-
- self.ui = load_ui('layer_style_editor.ui', self,
- directory=os.path.dirname(__file__))
-
- connect_kwargs = {'alpha': dict(value_range=(0, 1)),
- 'size_scaling': dict(value_range=(0.1, 10), log=True),
- 'density_contrast': dict(value_range=(0, 1)),
- 'vector_scaling': dict(value_range=(0.1, 10), log=True)}
- self._connections = autoconnect_callbacks_to_qt(layer.state, self.ui, connect_kwargs)
-
- self._connection_dpi = connect_value(layer.state.viewer_state, 'dpi', self.ui.value_dpi,
- value_range=(12, 144), log=True)
-
- fix_tab_widget_fontsize(self.ui.tab_widget)
-
- self.layer_state = layer.state
-
- self.layer_state.add_callback('markers_visible', self._update_markers_visible)
- self.layer_state.add_callback('line_visible', self._update_line_visible)
- self.layer_state.add_callback('xerr_visible', self._update_xerr_visible)
- self.layer_state.add_callback('yerr_visible', self._update_yerr_visible)
- self.layer_state.add_callback('vector_visible', self._update_vectors_visible)
-
- self.layer_state.add_callback('cmap_mode', self._update_cmap_mode)
- self.layer_state.add_callback('size_mode', self._update_size_mode)
- self.layer_state.add_callback('vector_mode', self._update_vector_mode)
-
- self.layer_state.add_callback('density_map', self._update_size_mode)
- self.layer_state.add_callback('density_map', self._update_warnings)
- self.layer_state.add_callback('density_map', self._update_checkboxes)
-
- self.layer_state.viewer_state.add_callback('x_att', self._update_checkboxes)
- self.layer_state.viewer_state.add_callback('y_att', self._update_checkboxes)
- if hasattr(self.layer_state.viewer_state, 'plot_mode'):
- self.layer_state.viewer_state.add_callback('plot_mode', self._update_vectors_visible)
-
- self.layer_state.add_callback('layer', self._update_warnings)
-
- self._update_markers_visible()
- self._update_line_visible()
- self._update_xerr_visible()
- self._update_yerr_visible()
- self._update_vectors_visible()
-
- self._update_size_mode()
- self._update_vector_mode()
- self._update_cmap_mode()
-
- self._update_checkboxes()
-
- self._update_warnings()
-
- def _update_warnings(self, *args):
-
- if self.layer_state.layer is None:
- n_points = 0
- else:
- n_points = np.prod(self.layer_state.layer.shape)
-
- warning = " (may be slow given data size)"
-
- for combo, threshold in [(self.ui.combosel_size_mode, 10000),
- (self.ui.combosel_cmap_mode, 50000)]:
-
- if n_points > threshold and not self.layer_state.density_map:
- for item in range(combo.count()):
- text = combo.itemText(item)
- if text != 'Fixed':
- combo.setItemText(item, text + warning)
- combo.setItemData(item, QtGui.QBrush(Qt.red), Qt.TextColorRole)
- else:
- for item in range(combo.count()):
- text = combo.itemText(item)
- if text != 'Fixed':
- if warning in text:
- combo.setItemText(item, text.replace(warning, ''))
- combo.setItemData(item, QtGui.QBrush(), Qt.TextColorRole)
-
- if n_points > 10000:
- self.ui.label_warning_errorbar.show()
- else:
- self.ui.label_warning_errorbar.hide()
-
- if n_points > 10000:
- self.ui.label_warning_vector.show()
- else:
- self.ui.label_warning_vector.hide()
-
- def _update_size_mode(self, size_mode=None):
-
- visible = not self.layer_state.density_map and not self.layer_state.size_mode == 'Fixed'
- self.ui.label_size_attribute.setVisible(visible)
- self.ui.combosel_size_att.setVisible(visible)
- self.ui.label_size_limits.setVisible(visible)
- self.ui.valuetext_size_vmin.setVisible(visible)
- self.ui.valuetext_size_vmax.setVisible(visible)
- self.ui.button_flip_size.setVisible(visible)
-
- visible = not self.layer_state.density_map and self.layer_state.size_mode == 'Fixed'
- self.ui.value_size.setVisible(visible)
-
- density = self.layer_state.density_map
- self.ui.value_dpi.setVisible(density)
- self.ui.label_dpi.setVisible(density)
- self.ui.label_stretch.setVisible(density)
- self.ui.combosel_stretch.setVisible(density)
- self.ui.value_density_contrast.setVisible(density)
- self.ui.label_contrast.setVisible(density)
- self.ui.combosel_size_mode.setVisible(not density)
- self.ui.value_size_scaling.setVisible(not density)
- self.ui.label_size_mode.setVisible(not density)
- self.ui.label_size_scaling.setVisible(not density)
- self.ui.label_fill.setVisible(not density)
- self.ui.bool_fill.setVisible(not density)
-
- def _update_markers_visible(self, *args):
- self.ui.combosel_size_mode.setEnabled(self.layer_state.markers_visible)
- self.ui.value_size.setEnabled(self.layer_state.markers_visible)
- self.ui.combosel_size_att.setEnabled(self.layer_state.markers_visible)
- self.ui.valuetext_size_vmin.setEnabled(self.layer_state.markers_visible)
- self.ui.valuetext_size_vmax.setEnabled(self.layer_state.markers_visible)
- self.ui.button_flip_size.setEnabled(self.layer_state.markers_visible)
- self.ui.value_size_scaling.setEnabled(self.layer_state.markers_visible)
- self.ui.value_dpi.setEnabled(self.layer_state.markers_visible)
- self.ui.combosel_stretch.setEnabled(self.layer_state.markers_visible)
- self.ui.label_size_scaling.setEnabled(self.layer_state.markers_visible)
- self.ui.combosel_points_mode.setEnabled(self.layer_state.markers_visible)
- self.ui.value_density_contrast.setEnabled(self.layer_state.markers_visible)
-
- def _update_checkboxes(self, *args):
-
- if isinstance(self.layer_state.layer, BaseData):
- layer = self.layer_state.layer
- else:
- layer = self.layer_state.layer.data
-
- try:
- x_datetime = layer.get_kind(self.layer_state.viewer_state.x_att) == 'datetime'
- except IncompatibleAttribute:
- x_datetime = False
-
- try:
- y_datetime = layer.get_kind(self.layer_state.viewer_state.y_att) == 'datetime'
- except IncompatibleAttribute:
- y_datetime = False
-
- for checkbox in [self.ui.bool_line_visible, self.ui.bool_xerr_visible,
- self.ui.bool_yerr_visible, self.ui.bool_vector_visible]:
- if self.layer_state.density_map:
- checkbox.setEnabled(False)
- checkbox.setToolTip('Not available with density map')
- else:
- if ((x_datetime and checkbox in (self.ui.bool_xerr_visible, self.ui.bool_vector_visible)) or
- (y_datetime and checkbox in (self.ui.bool_yerr_visible, self.ui.bool_vector_visible))):
- checkbox.setEnabled(False)
- checkbox.setToolTip('Not available when using datetime attribute')
- else:
- checkbox.setEnabled(True)
- checkbox.setToolTip('')
-
- def _update_line_visible(self, *args):
- self.ui.value_linewidth.setEnabled(self.layer_state.line_visible)
- self.ui.combosel_linestyle.setEnabled(self.layer_state.line_visible)
-
- def _update_xerr_visible(self, *args):
- self.ui.combosel_xerr_att.setEnabled(self.layer_state.xerr_visible)
-
- def _update_yerr_visible(self, *args):
- self.ui.combosel_yerr_att.setEnabled(self.layer_state.yerr_visible)
-
- def _update_vectors_visible(self, *args):
- viewer_state = self.layer_state.viewer_state
- is_rect = not hasattr(viewer_state, 'plot_mode') or viewer_state.plot_mode == 'rectilinear'
- self.ui.combosel_vector_mode.setEnabled(self.layer_state.vector_visible and is_rect)
- self.ui.combosel_vx_att.setEnabled(self.layer_state.vector_visible)
- self.ui.combosel_vy_att.setEnabled(self.layer_state.vector_visible)
- self.ui.value_vector_scaling.setEnabled(self.layer_state.vector_visible)
- self.ui.combosel_vector_origin.setEnabled(self.layer_state.vector_visible)
- self.ui.bool_vector_arrowhead.setEnabled(self.layer_state.vector_visible)
-
- def _update_vector_mode(self, vector_mode=None):
- if self.layer_state.vector_mode == 'Cartesian':
- self.ui.label_vector_x.setText('vx')
- self.ui.label_vector_y.setText('vy')
- elif self.layer_state.vector_mode == 'Polar':
- self.ui.label_vector_x.setText('angle (deg)')
- self.ui.label_vector_y.setText('length')
-
- def _update_cmap_mode(self, cmap_mode=None):
-
- if self.layer_state.cmap_mode == 'Fixed':
- self.ui.label_cmap_attribute.hide()
- self.ui.combosel_cmap_att.hide()
- self.ui.label_cmap_limits.hide()
- self.ui.valuetext_cmap_vmin.hide()
- self.ui.valuetext_cmap_vmax.hide()
- self.ui.button_flip_cmap.hide()
- self.ui.combodata_cmap.hide()
- self.ui.label_colormap.hide()
- self.ui.color_color.show()
- else:
- self.ui.label_cmap_attribute.show()
- self.ui.combosel_cmap_att.show()
- self.ui.label_cmap_limits.show()
- self.ui.valuetext_cmap_vmin.show()
- self.ui.valuetext_cmap_vmax.show()
- self.ui.button_flip_cmap.show()
- self.ui.combodata_cmap.show()
- self.ui.label_colormap.show()
- self.ui.color_color.hide()
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.scatter.qt.layer_style_editor is deprecated, use glue_qt.viewers.scatter.layer_style_editor instead', GlueDeprecationWarning)
+from glue_qt.viewers.scatter.layer_style_editor import * # noqa
diff --git a/glue/viewers/scatter/qt/layer_style_editor.ui b/glue/viewers/scatter/qt/layer_style_editor.ui
deleted file mode 100644
index cad731176..000000000
--- a/glue/viewers/scatter/qt/layer_style_editor.ui
+++ /dev/null
@@ -1,1054 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 330
- 296
-
-
-
- Form
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
- 0
-
-
- Qt::ElideNone
-
-
-
- Color
-
-
-
- 10
-
-
- 3
-
-
- 10
-
-
- 3
-
-
- 10
-
-
- 5
-
-
-
-
-
- 100
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- opacity
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 1
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
- -
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
-
- 80
- 16777215
-
-
-
-
- -
-
-
- padding: 0px
-
-
- ⇄
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- color
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- limits
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- colormap
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- attribute
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
-
-
-
-
- Points
-
-
-
- 10
-
-
- 3
-
-
- 10
-
-
- 3
-
-
- 10
-
-
- 5
-
- -
-
-
-
- 120
- 16777215
-
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- show
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- Qt::LeftToRight
-
-
- limits
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- padding: 0px
-
-
- ⇄
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- dpi
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -
-
-
-
- 75
- true
-
-
-
- Qt::LeftToRight
-
-
- attribute
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- Qt::LeftToRight
-
-
- scaling
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- Qt::LeftToRight
-
-
- size
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 1
-
-
-
-
- -
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- 100
-
-
- 50
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 80
- 16777215
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- type
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- stretch
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 16777215
- 16777215
-
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- contrast
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- fill
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- Line
-
-
-
- 10
-
-
- 3
-
-
- 10
-
-
- 3
-
-
- 10
-
-
- 5
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 1
-
-
-
-
- -
-
-
- 1
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- width
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- -
-
-
-
- 75
- true
-
-
-
- style
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- show
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- Errors
-
-
-
- 10
-
-
- 3
-
-
- 10
-
-
- 3
-
-
- 10
-
-
- 5
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 1
-
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- show y
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- show x
-
-
-
- -
-
-
- color: #BB2200
-
-
- Warning: adding errorbars may be slow
-
-
- Qt::AlignCenter
-
-
-
-
-
-
-
- Vectors
-
-
-
- 10
-
-
- 3
-
-
- 10
-
-
- 3
-
-
- 10
-
-
- 5
-
- -
-
-
- Show arrow
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- show
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- vx
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 16777215
- 16777215
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- arrow
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -
-
-
-
- 75
- true
-
-
-
- type
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- vy
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- origin
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 1
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- scaling
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- color: #BB2200
-
-
- Warning: adding vectors may be slow
-
-
- Qt::AlignCenter
-
-
- false
-
-
-
-
-
-
-
-
-
-
-
- QColorBox
- QLabel
-
-
-
- QColormapCombo
- QComboBox
-
-
-
-
-
-
diff --git a/glue/viewers/scatter/qt/options_widget.py b/glue/viewers/scatter/qt/options_widget.py
index 8d26dbdd2..fe1e5fc51 100644
--- a/glue/viewers/scatter/qt/options_widget.py
+++ b/glue/viewers/scatter/qt/options_widget.py
@@ -1,118 +1,4 @@
-import os
-
-from qtpy import QtWidgets
-
-from echo.qt import autoconnect_callbacks_to_qt
-from glue.utils.qt import load_ui, fix_tab_widget_fontsize
-from glue.viewers.matplotlib.state import MatplotlibDataViewerState
-
-__all__ = ['ScatterOptionsWidget']
-
-
-def _get_labels(proj):
- if proj == 'rectilinear':
- return 'x axis', 'y axis'
- elif proj == 'polar':
- return 'theta', 'radius'
- elif proj in ['aitoff', 'hammer', 'lambert', 'mollweide']:
- return 'long', 'lat'
- else:
- return 'axis 1', 'axis 2'
-
-
-class ScatterOptionsWidget(QtWidgets.QWidget):
-
- def __init__(self, viewer_state, session, parent=None):
-
- super(ScatterOptionsWidget, self).__init__(parent=parent)
-
- self.ui = load_ui('options_widget.ui', self,
- directory=os.path.dirname(__file__))
-
- fix_tab_widget_fontsize(self.ui.tab_widget)
-
- self._connections = autoconnect_callbacks_to_qt(viewer_state, self.ui)
- self._connections_axes = autoconnect_callbacks_to_qt(viewer_state, self.ui.axes_editor.ui)
- connect_kwargs = {'alpha': dict(value_range=(0, 1))}
- self._connections_legend = autoconnect_callbacks_to_qt(viewer_state.legend, self.ui.legend_editor.ui, connect_kwargs)
-
- self.viewer_state = viewer_state
-
- viewer_state.add_callback('x_att', self._update_x_attribute)
- viewer_state.add_callback('y_att', self._update_y_attribute)
- viewer_state.add_callback('plot_mode', self._update_plot_mode)
- viewer_state.add_callback('angle_unit', self._update_x_attribute)
-
- self.session = session
- self.ui.axes_editor.button_apply_all.clicked.connect(self._apply_all_viewers)
-
- # Without this, log buttons will be enabled when the application starts
- # regardless of the current plot mode
- self._update_x_attribute()
- self._update_y_attribute()
-
- # Make sure that the UI is consistent with the plot mode that's selected
- self._update_plot_mode()
-
- def _apply_all_viewers(self):
- for tab in self.session.application.viewers:
- for viewer in tab:
- if isinstance(viewer.state, MatplotlibDataViewerState):
- viewer.state.update_axes_settings_from(self.viewer_state)
-
- def _update_x_attribute(self, *args):
- # If at least one of the components is categorical or a date, disable log button
- log_enabled = ('categorical' not in self.viewer_state.x_kinds and self.viewer_state.plot_mode not in ['aitoff', 'hammer', 'lambert', 'mollweide', 'polar'])
- self.ui.bool_x_log.setEnabled(log_enabled)
- self.ui.bool_x_log_.setEnabled(log_enabled)
- if not log_enabled:
- self.ui.bool_x_log.setChecked(False)
- self.ui.bool_x_log_.setChecked(False)
-
- def _update_y_attribute(self, *args):
- # If at least one of the components is categorical or a date, disable log button
- log_enabled = ('categorical' not in self.viewer_state.y_kinds and self.viewer_state.plot_mode not in ['aitoff', 'hammer', 'lambert', 'mollweide', 'polar'])
- self.ui.bool_y_log.setEnabled(log_enabled)
- self.ui.bool_y_log_.setEnabled(log_enabled)
- if not log_enabled:
- self.ui.bool_y_log.setChecked(False)
- self.ui.bool_y_log_.setChecked(False)
-
- def _update_plot_mode(self, *args):
- x_label, y_label = _get_labels(self.viewer_state.plot_mode)
- self.ui.x_lab.setText(x_label)
- self.ui.x_lab_2.setText(x_label)
- self.ui.y_lab.setText(y_label)
- self.ui.y_lab_2.setText(y_label)
- lim_enabled = self.viewer_state.plot_mode not in ['aitoff', 'hammer', 'lambert', 'mollweide']
- is_polar = self.viewer_state.using_polar
- is_rect = self.viewer_state.using_rectilinear
- self.ui.valuetext_x_min.setEnabled(lim_enabled)
- self.ui.valuetext_x_max.setEnabled(lim_enabled)
- self.ui.valuetext_y_min.setEnabled(lim_enabled)
- self.ui.valuetext_y_max.setEnabled(lim_enabled)
- self.ui.button_full_circle.setVisible(False)
- self.ui.angle_unit_lab.setVisible(not is_rect)
- self.ui.combosel_angle_unit.setVisible(not is_rect)
- self.ui.x_lab_2.setVisible(not is_polar)
- self.ui.valuetext_x_min.setVisible(not is_polar)
- self.ui.button_flip_x.setVisible(not is_polar)
- self.ui.valuetext_x_max.setVisible(not is_polar)
- self.ui.bool_x_log.setVisible(not is_polar)
-
- # In polar mode, the axis labels are shown in ticks rather than using the plot axis
- # so we adjust the axes editor to account for this
- axes_ui = self.ui.axes_editor.ui
- axes_ui.label_3.setVisible(not is_polar)
- axes_ui.label_4.setVisible(not is_polar)
- axes_ui.value_x_axislabel_size.setVisible(not is_polar)
- axes_ui.value_y_axislabel_size.setVisible(not is_polar)
- axes_ui.combosel_x_axislabel_weight.setVisible(not is_polar)
- axes_ui.combosel_y_axislabel_weight.setVisible(not is_polar)
- axes_ui.label_2.setText("Θlabel" if is_polar else "xlabel")
- axes_ui.label_6.setText("rlabel" if is_polar else "ylabel")
- axes_ui.label.setText("Θ" if is_polar else "x")
- axes_ui.label_10.setText("r" if is_polar else "y")
-
- self._update_x_attribute()
- self._update_y_attribute()
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.scatter.qt.options_widget is deprecated, use glue_qt.viewers.scatter.options_widget instead', GlueDeprecationWarning)
+from glue_qt.viewers.scatter.options_widget import * # noqa
diff --git a/glue/viewers/scatter/qt/options_widget.ui b/glue/viewers/scatter/qt/options_widget.ui
deleted file mode 100644
index 245123fcf..000000000
--- a/glue/viewers/scatter/qt/options_widget.ui
+++ /dev/null
@@ -1,397 +0,0 @@
-
-
- Widget
-
-
-
- 0
- 0
- 389
- 221
-
-
-
- 2D Scatter
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
- QTabWidget::North
-
-
- 0
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
-
- General
-
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 5
-
-
-
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- type
-
-
-
- -
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 5
-
-
-
-
- -
-
-
- log
-
-
- true
-
-
-
- -
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- y axis
-
-
-
- -
-
-
- log
-
-
- true
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- x axis
-
-
-
- -
-
-
- -
-
-
- <html><head/><body><p><span style=" font-weight:600;">unit</span></p></body></html>
-
-
-
-
-
-
-
- Limits
-
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 5
-
- -
-
-
-
- 75
- true
-
-
-
- x axis
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- log
-
-
- true
-
-
-
- -
-
-
- -
-
-
-
- 75
- true
-
-
-
- y axis
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- padding: 0px
-
-
- ⇄
-
-
-
- -
-
-
- padding: 0px
-
-
- ⇄
-
-
-
- -
-
-
- log
-
-
- true
-
-
-
- -
-
-
- -
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 5
-
-
-
-
- -
-
-
- true
-
-
- full circle
-
-
-
-
-
-
-
- Axes
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
-
-
-
-
- Legend
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
-
-
-
-
-
-
-
-
-
- AxesEditorWidget
- QWidget
- glue.viewers.matplotlib.qt.axes_editor
-
-
- LegendEditorWidget
- QWidget
- glue.viewers.matplotlib.qt.legend_editor
-
-
-
-
-
diff --git a/glue/viewers/scatter/qt/tests/__init__.py b/glue/viewers/scatter/qt/tests/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/glue/viewers/scatter/qt/tests/data/scatter_and_line_v1.glu b/glue/viewers/scatter/qt/tests/data/scatter_and_line_v1.glu
deleted file mode 100644
index dcf452518..000000000
--- a/glue/viewers/scatter/qt/tests/data/scatter_and_line_v1.glu
+++ /dev/null
@@ -1,322 +0,0 @@
-{
- "CallbackList": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ScatterLayerState"
- ]
- },
- "CallbackList_0": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ScatterLayerState_0"
- ]
- },
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoBAAAAAAAAAAIAAAAAAAAAAwAAAAAAAAA="
- },
- "units": ""
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoCAAAAAAAAAAMAAAAAAAAABAAAAAAAAAA="
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0",
- "b"
- ],
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component_0"
- ],
- "data": [
- "table"
- ],
- "groups": [],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0"
- ],
- "subset_group_count": 0
- },
- "LinearSegmentedColormap": {
- "_type": "matplotlib.colors.LinearSegmentedColormap",
- "cmap": "gray"
- },
- "Pixel Axis 0 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [x]"
- },
- "ScatterLayerState": {
- "_type": "glue.viewers.scatter.state.ScatterLayerState",
- "values": {
- "alpha": 0.7777777777777778,
- "cmap": "LinearSegmentedColormap",
- "cmap_att": "a",
- "cmap_mode": "st__Fixed",
- "cmap_vmax": 3.0,
- "cmap_vmin": 1.0,
- "color": "st__#404040",
- "layer": "table",
- "linestyle": "st__solid",
- "linewidth": 1,
- "size": 3,
- "size_att": "a",
- "size_mode": "st__Fixed",
- "size_scaling": 1,
- "size_vmax": 3.0,
- "size_vmin": 1.0,
- "style": "st__Scatter",
- "visible": true,
- "xerr_att": "a",
- "xerr_visible": false,
- "yerr_att": "a",
- "yerr_visible": false,
- "zorder": 1
- }
- },
- "ScatterLayerState_0": {
- "_type": "glue.viewers.scatter.state.ScatterLayerState",
- "values": {
- "alpha": 0.7777777777777778,
- "cmap": "LinearSegmentedColormap",
- "cmap_att": "a",
- "cmap_mode": "st__Fixed",
- "cmap_vmax": 3.0,
- "cmap_vmin": 1.0,
- "color": "st__#404040",
- "layer": "table",
- "linestyle": "st__solid",
- "linewidth": 1,
- "size": 3,
- "size_att": "a",
- "size_mode": "st__Fixed",
- "size_scaling": 1,
- "size_vmax": 3.0,
- "size_vmin": 1.0,
- "style": "st__Line",
- "visible": true,
- "xerr_att": "a",
- "xerr_visible": false,
- "yerr_att": "a",
- "yerr_visible": false,
- "zorder": 1
- }
- },
- "ScatterViewer": {
- "_protocol": 1,
- "_type": "glue.viewers.scatter.qt.data_viewer.ScatterViewer",
- "layers": [
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "state": "ScatterLayerState"
- }
- ],
- "pos": [
- 0,
- 0
- ],
- "session": "Session",
- "size": [
- 605,
- 444
- ],
- "state": {
- "values": {
- "aspect": "st__auto",
- "layers": "CallbackList",
- "x_att": "a",
- "x_log": false,
- "x_max": 3.0,
- "x_min": 1.0,
- "y_att": "b",
- "y_log": false,
- "y_max": 4.0,
- "y_min": 2.0
- }
- }
- },
- "ScatterViewer_0": {
- "_protocol": 1,
- "_type": "glue.viewers.scatter.qt.data_viewer.ScatterViewer",
- "layers": [
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "state": "ScatterLayerState_0"
- }
- ],
- "pos": [
- 605,
- 0
- ],
- "session": "Session",
- "size": [
- 600,
- 400
- ],
- "state": {
- "values": {
- "aspect": "st__auto",
- "layers": "CallbackList_0",
- "x_att": "a",
- "x_log": false,
- "x_max": 3.0,
- "x_min": 1.0,
- "y_att": "b",
- "y_log": false,
- "y_max": 4.0,
- "y_min": 2.0
- }
- }
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue.core.data_exporters",
- "glue.viewers.histogram",
- "glue.io.formats.fits",
- "glue_exp.tools.zoom_buttons",
- "glue.viewers.scatter",
- "glue.plugins.export_d3po",
- "glue.plugins.exporters.plotly",
- "glue_samp",
- "glue_exp.importers.webcam",
- "glue.viewers.table",
- "glue_aladin",
- "glue.plugins.tools.spectrum_tool",
- "glue_vispy_viewers.volume",
- "glue.plugins.dendro_viewer",
- "glue.viewers.image",
- "glue_exp.tools.contour_selection",
- "glue_wwt",
- "glue.plugins.tools.pv_slicer",
- "glue_exp.tools.floodfill_selection",
- "glue_exp.importers.vizier",
- "glue_vispy_viewers.scatter",
- "glue.plugins.coordinate_helpers"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- [
- "ScatterViewer",
- "ScatterViewer_0"
- ]
- ]
- },
- "a": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "a"
- },
- "b": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "b"
- },
- "table": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "a",
- "Component"
- ],
- [
- "Pixel Axis 0 [x]",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "b",
- "Component_0"
- ]
- ],
- "coords": "Coordinates",
- "label": "table",
- "primary_owner": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0",
- "b"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.7777777777777778,
- "color": "#404040",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [],
- "uuid": "3755b390-c67e-44a0-b5b5-ebfc709c859e"
- }
-}
\ No newline at end of file
diff --git a/glue/viewers/scatter/qt/tests/data/scatter_v0.glu b/glue/viewers/scatter/qt/tests/data/scatter_v0.glu
deleted file mode 100644
index 74e520951..000000000
--- a/glue/viewers/scatter/qt/tests/data/scatter_v0.glu
+++ /dev/null
@@ -1,449 +0,0 @@
-{
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGY4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoAAAAAAADwP5qZmZmZmck/AAAAAAAA8L8="
- },
- "units": ""
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoDAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAA="
- },
- "units": ""
- },
- "Component_1": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGY4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoAAAAAAAAQQJqZmZmZmdk/AAAAAAAAFEA="
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0",
- "b",
- "c"
- ],
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component_0",
- "Component_1"
- ],
- "data": [
- "basic"
- ],
- "groups": [
- "Subset 1_0",
- "Subset 2_0"
- ],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0"
- ],
- "subset_group_count": 2
- },
- "Pixel Axis 0 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [x]"
- },
- "PolygonalROI": {
- "_type": "glue.core.roi.PolygonalROI",
- "vx": [
- 0.010048309178743997,
- 0.22106280193236705,
- 0.22106280193236705,
- 0.010048309178743997,
- 0.010048309178743997
- ],
- "vy": [
- 1.9849289099526066,
- 1.9849289099526066,
- 2.167298578199052,
- 2.167298578199052,
- 1.9849289099526066
- ]
- },
- "PolygonalROI_0": {
- "_type": "glue.core.roi.PolygonalROI",
- "vx": [
- -1.04,
- 0.4521739130434783,
- 0.4521739130434783,
- -1.04,
- -1.04
- ],
- "vy": [
- 1.9997156398104265,
- 1.9997156398104265,
- 2.2806635071090047,
- 2.2806635071090047,
- 1.9997156398104265
- ]
- },
- "RoiSubsetState": {
- "_type": "glue.core.subset.RoiSubsetState",
- "roi": "PolygonalROI",
- "xatt": "a",
- "yatt": "b"
- },
- "RoiSubsetState_0": {
- "_type": "glue.core.subset.RoiSubsetState",
- "roi": "PolygonalROI_0",
- "xatt": "a",
- "yatt": "b"
- },
- "ScatterWidget": {
- "_type": "glue.viewers.scatter.qt.viewer_widget.ScatterWidget",
- "layers": [
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "layer": "basic",
- "visible": true,
- "xatt": "a",
- "yatt": "b",
- "zorder": 1
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "layer": "Subset 1",
- "visible": true,
- "xatt": "a",
- "yatt": "b",
- "zorder": 2
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "layer": "Subset 2",
- "visible": true,
- "xatt": "a",
- "yatt": "b",
- "zorder": 3
- }
- ],
- "pos": [
- 0,
- 0
- ],
- "properties": {
- "hidden": false,
- "xatt": "a",
- "xflip": false,
- "xlog": false,
- "xmax": 1.04,
- "xmin": -1.04,
- "yatt": "b",
- "yflip": false,
- "ylog": false,
- "ymax": 3.02,
- "ymin": 1.98
- },
- "session": "Session",
- "size": [
- 600,
- 400
- ]
- },
- "ScatterWidget_0": {
- "_type": "glue.viewers.scatter.qt.viewer_widget.ScatterWidget",
- "layers": [
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "layer": "basic",
- "visible": true,
- "xatt": "a",
- "yatt": "c",
- "zorder": 1
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "layer": "Subset 1",
- "visible": false,
- "xatt": "a",
- "yatt": "c",
- "zorder": 2
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "layer": "Subset 2",
- "visible": true,
- "xatt": "a",
- "yatt": "c",
- "zorder": 3
- }
- ],
- "pos": [
- 600,
- 0
- ],
- "properties": {
- "hidden": false,
- "xatt": "a",
- "xflip": false,
- "xlog": true,
- "xmax": 1.05,
- "xmin": 9.5e-06,
- "yatt": "c",
- "yflip": false,
- "ylog": true,
- "ymax": 5.25,
- "ymin": 0.38
- },
- "session": "Session",
- "size": [
- 600,
- 400
- ]
- },
- "ScatterWidget_1": {
- "_type": "glue.viewers.scatter.qt.viewer_widget.ScatterWidget",
- "layers": [
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "layer": "basic",
- "visible": true,
- "xatt": "b",
- "yatt": "a",
- "zorder": 1
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "layer": "Subset 1",
- "visible": true,
- "xatt": "b",
- "yatt": "a",
- "zorder": 2
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "layer": "Subset 2",
- "visible": false,
- "xatt": "b",
- "yatt": "a",
- "zorder": 3
- }
- ],
- "pos": [
- 0,
- 400
- ],
- "properties": {
- "hidden": false,
- "xatt": "b",
- "xflip": false,
- "xlog": false,
- "xmax": 5.0,
- "xmin": 0.0,
- "yatt": "a",
- "yflip": true,
- "ylog": false,
- "ymax": 5.0,
- "ymin": -5.0
- },
- "session": "Session",
- "size": [
- 600,
- 400
- ]
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "Subset 1": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 1_0",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- }
- },
- "Subset 1_0": {
- "_type": "glue.core.subset_group.SubsetGroup",
- "label": "Subset 1",
- "state": "RoiSubsetState",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- },
- "subsets": [
- "Subset 1"
- ]
- },
- "Subset 2": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 2_0",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#33a02c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- }
- },
- "Subset 2_0": {
- "_type": "glue.core.subset_group.SubsetGroup",
- "label": "Subset 2",
- "state": "RoiSubsetState_0",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#33a02c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- },
- "subsets": [
- "Subset 2"
- ]
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue.viewers.scatter"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- [
- "ScatterWidget",
- "ScatterWidget_0",
- "ScatterWidget_1"
- ]
- ]
- },
- "a": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "a"
- },
- "b": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "b"
- },
- "basic": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "a",
- "Component"
- ],
- [
- "Pixel Axis 0 [x]",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "b",
- "Component_0"
- ],
- [
- "c",
- "Component_1"
- ]
- ],
- "coords": "Coordinates",
- "label": "basic",
- "primary_owner": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0",
- "b",
- "c"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "0.35",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [
- "Subset 1",
- "Subset 2"
- ],
- "uuid": "dde080dc-a65a-4988-bed9-c0cb90ff91a8"
- },
- "c": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "c"
- }
-}
\ No newline at end of file
diff --git a/glue/viewers/scatter/qt/tests/data/scatter_v1.glu b/glue/viewers/scatter/qt/tests/data/scatter_v1.glu
deleted file mode 100644
index c1f224894..000000000
--- a/glue/viewers/scatter/qt/tests/data/scatter_v1.glu
+++ /dev/null
@@ -1,578 +0,0 @@
-{
- "CallbackList": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ScatterLayerState",
- "ScatterLayerState_0",
- "ScatterLayerState_1"
- ]
- },
- "CallbackList_0": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ScatterLayerState_2",
- "ScatterLayerState_3",
- "ScatterLayerState_4"
- ]
- },
- "CallbackList_1": {
- "_type": "glue.external.echo.list.CallbackList",
- "values": [
- "ScatterLayerState_5",
- "ScatterLayerState_6",
- "ScatterLayerState_7"
- ]
- },
- "Component": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGY4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoAAAAAAADwP5qZmZmZmck/AAAAAAAA8L8="
- },
- "units": ""
- },
- "Component_0": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGk4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoDAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAA="
- },
- "units": ""
- },
- "Component_1": {
- "_type": "glue.core.component.Component",
- "data": {
- "_type": "numpy.ndarray",
- "data": "k05VTVBZAQBGAHsnZGVzY3InOiAnPGY4JywgJ2ZvcnRyYW5fb3JkZXInOiBGYWxzZSwgJ3NoYXBlJzogKDMsKSwgfSAgICAgICAgICAgIAoAAAAAAAAQQJqZmZmZmdk/AAAAAAAAFEA="
- },
- "units": ""
- },
- "CoordinateComponent": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": false
- },
- "CoordinateComponentLink": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]"
- ]
- },
- "CoordinateComponentLink_0": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "World 0"
- ],
- "index": 0,
- "pix2world": false,
- "to": [
- "Pixel Axis 0 [x]"
- ]
- },
- "CoordinateComponentLink_1": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponentLink_2": {
- "_type": "glue.core.component_link.CoordinateComponentLink",
- "coords": "Coordinates",
- "frm": [
- "Pixel Axis 0 [x]"
- ],
- "index": 0,
- "pix2world": true,
- "to": [
- "World 0"
- ]
- },
- "CoordinateComponent_0": {
- "_type": "glue.core.component.CoordinateComponent",
- "axis": 0,
- "world": true
- },
- "Coordinates": {
- "_type": "glue.core.coordinates.Coordinates"
- },
- "DataCollection": {
- "_protocol": 3,
- "_type": "glue.core.data_collection.DataCollection",
- "cids": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0",
- "b",
- "c"
- ],
- "components": [
- "Component",
- "CoordinateComponent",
- "CoordinateComponent_0",
- "Component_0",
- "Component_1"
- ],
- "data": [
- "basic"
- ],
- "groups": [
- "Subset 1",
- "Subset 2"
- ],
- "links": [
- "CoordinateComponentLink",
- "CoordinateComponentLink_0",
- "CoordinateComponentLink_1",
- "CoordinateComponentLink_2"
- ],
- "subset_group_count": 2
- },
- "Pixel Axis 0 [x]": {
- "_type": "glue.core.component_id.PixelComponentID",
- "axis": 0,
- "hidden": true,
- "label": "Pixel Axis 0 [x]"
- },
- "PolygonalROI": {
- "_type": "glue.core.roi.PolygonalROI",
- "vx": [
- 0.010048309178743997,
- 0.22106280193236705,
- 0.22106280193236705,
- 0.010048309178743997,
- 0.010048309178743997
- ],
- "vy": [
- 1.9849289099526066,
- 1.9849289099526066,
- 2.167298578199052,
- 2.167298578199052,
- 1.9849289099526066
- ]
- },
- "PolygonalROI_0": {
- "_type": "glue.core.roi.PolygonalROI",
- "vx": [
- -1.04,
- 0.4521739130434783,
- 0.4521739130434783,
- -1.04,
- -1.04
- ],
- "vy": [
- 1.9997156398104265,
- 1.9997156398104265,
- 2.2806635071090047,
- 2.2806635071090047,
- 1.9997156398104265
- ]
- },
- "RoiSubsetState": {
- "_type": "glue.core.subset.RoiSubsetState",
- "roi": "PolygonalROI",
- "xatt": "a",
- "yatt": "b"
- },
- "RoiSubsetState_0": {
- "_type": "glue.core.subset.RoiSubsetState",
- "roi": "PolygonalROI_0",
- "xatt": "a",
- "yatt": "b"
- },
- "ScatterLayerState": {
- "_type": "glue.viewers.scatter.state.ScatterLayerState",
- "values": {
- "alpha": 0.8,
- "color": "st__0.35",
- "layer": "basic",
- "size": 3,
- "visible": true,
- "zorder": 2
- }
- },
- "ScatterLayerState_0": {
- "_type": "glue.viewers.scatter.state.ScatterLayerState",
- "values": {
- "alpha": 0.5,
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "size": 7,
- "visible": true,
- "zorder": 3
- }
- },
- "ScatterLayerState_1": {
- "_type": "glue.viewers.scatter.state.ScatterLayerState",
- "values": {
- "alpha": 0.5,
- "color": "st__#33a02c",
- "layer": "Subset 2_0",
- "size": 7,
- "visible": true,
- "zorder": 4
- }
- },
- "ScatterLayerState_2": {
- "_type": "glue.viewers.scatter.state.ScatterLayerState",
- "values": {
- "alpha": 0.8,
- "color": "st__0.35",
- "layer": "basic",
- "size": 3,
- "visible": true,
- "zorder": 2
- }
- },
- "ScatterLayerState_3": {
- "_type": "glue.viewers.scatter.state.ScatterLayerState",
- "values": {
- "alpha": 0.5,
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "size": 7,
- "visible": false,
- "zorder": 3
- }
- },
- "ScatterLayerState_4": {
- "_type": "glue.viewers.scatter.state.ScatterLayerState",
- "values": {
- "alpha": 0.5,
- "color": "st__#33a02c",
- "layer": "Subset 2_0",
- "size": 7,
- "visible": true,
- "zorder": 4
- }
- },
- "ScatterLayerState_5": {
- "_type": "glue.viewers.scatter.state.ScatterLayerState",
- "values": {
- "alpha": 0.8,
- "color": "st__0.35",
- "layer": "basic",
- "size": 3,
- "visible": true,
- "zorder": 2
- }
- },
- "ScatterLayerState_6": {
- "_type": "glue.viewers.scatter.state.ScatterLayerState",
- "values": {
- "alpha": 0.5,
- "color": "st__#e31a1c",
- "layer": "Subset 1_0",
- "size": 7,
- "visible": true,
- "zorder": 3
- }
- },
- "ScatterLayerState_7": {
- "_type": "glue.viewers.scatter.state.ScatterLayerState",
- "values": {
- "alpha": 0.5,
- "color": "st__#33a02c",
- "layer": "Subset 2_0",
- "size": 7,
- "visible": false,
- "zorder": 4
- }
- },
- "ScatterViewer": {
- "_protocol": 1,
- "_type": "glue.viewers.scatter.qt.data_viewer.ScatterViewer",
- "layers": [
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "state": "ScatterLayerState"
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "state": "ScatterLayerState_0"
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "state": "ScatterLayerState_1"
- }
- ],
- "pos": [
- 0,
- 0
- ],
- "session": "Session",
- "size": [
- 600,
- 400
- ],
- "state": {
- "values": {
- "layers": "CallbackList",
- "x_att": "a",
- "x_log": false,
- "x_max": 1.04,
- "x_min": -1.04,
- "y_att": "b",
- "y_log": false,
- "y_max": 3.02,
- "y_min": 1.98
- }
- }
- },
- "ScatterViewer_0": {
- "_protocol": 1,
- "_type": "glue.viewers.scatter.qt.data_viewer.ScatterViewer",
- "layers": [
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "state": "ScatterLayerState_2"
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "state": "ScatterLayerState_3"
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "state": "ScatterLayerState_4"
- }
- ],
- "pos": [
- 600,
- 0
- ],
- "session": "Session",
- "size": [
- 600,
- 400
- ],
- "state": {
- "values": {
- "layers": "CallbackList_0",
- "x_att": "a",
- "x_log": true,
- "x_max": 1.05,
- "x_min": 9.5e-06,
- "y_att": "c",
- "y_log": true,
- "y_max": 5.25,
- "y_min": 0.38
- }
- }
- },
- "ScatterViewer_1": {
- "_protocol": 1,
- "_type": "glue.viewers.scatter.qt.data_viewer.ScatterViewer",
- "layers": [
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "state": "ScatterLayerState_5"
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "state": "ScatterLayerState_6"
- },
- {
- "_type": "glue.viewers.scatter.layer_artist.ScatterLayerArtist",
- "state": "ScatterLayerState_7"
- }
- ],
- "pos": [
- 0,
- 400
- ],
- "session": "Session",
- "size": [
- 600,
- 400
- ],
- "state": {
- "values": {
- "layers": "CallbackList_1",
- "x_att": "b",
- "x_log": false,
- "x_max": 5.0,
- "x_min": 0.0,
- "y_att": "a",
- "y_log": false,
- "y_max": 5.0,
- "y_min": -5.0
- }
- }
- },
- "Session": {
- "_type": "glue.core.session.Session"
- },
- "Subset 1": {
- "_type": "glue.core.subset_group.SubsetGroup",
- "label": "Subset 1",
- "state": "RoiSubsetState",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- },
- "subsets": [
- "Subset 1_0"
- ]
- },
- "Subset 1_0": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 1",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#e31a1c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- }
- },
- "Subset 2": {
- "_type": "glue.core.subset_group.SubsetGroup",
- "label": "Subset 2",
- "state": "RoiSubsetState_0",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#33a02c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- },
- "subsets": [
- "Subset 2_0"
- ]
- },
- "Subset 2_0": {
- "_type": "glue.core.subset_group.GroupedSubset",
- "group": "Subset 2",
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.5,
- "color": "#33a02c",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 7
- }
- },
- "World 0": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": true,
- "label": "World 0"
- },
- "__main__": {
- "_type": "glue.app.qt.application.GlueApplication",
- "data": "DataCollection",
- "plugins": [
- "glue.plugins.exporters.plotly",
- "specviz.app",
- "glue.plugins.coordinate_helpers",
- "glue.viewers.histogram",
- "glue.core.data_exporters",
- "glue.plugins.export_d3po",
- "glue_vispy_viewers.volume",
- "glue_vispy_viewers.scatter",
- "glue.viewers.table",
- "glue.viewers.image",
- "glue_medical",
- "glue.plugins.tools.spectrum_tool",
- "glue.plugins.tools.pv_slicer",
- "glue.viewers.scatter"
- ],
- "session": "Session",
- "tab_names": [
- "Tab 1"
- ],
- "viewers": [
- [
- "ScatterViewer",
- "ScatterViewer_0",
- "ScatterViewer_1"
- ]
- ]
- },
- "a": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "a"
- },
- "b": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "b"
- },
- "basic": {
- "_key_joins": [],
- "_protocol": 5,
- "_type": "glue.core.data.Data",
- "components": [
- [
- "a",
- "Component"
- ],
- [
- "Pixel Axis 0 [x]",
- "CoordinateComponent"
- ],
- [
- "World 0",
- "CoordinateComponent_0"
- ],
- [
- "b",
- "Component_0"
- ],
- [
- "c",
- "Component_1"
- ]
- ],
- "coords": "Coordinates",
- "label": "basic",
- "primary_owner": [
- "a",
- "Pixel Axis 0 [x]",
- "World 0",
- "b",
- "c"
- ],
- "style": {
- "_type": "glue.core.visual.VisualAttributes",
- "alpha": 0.8,
- "color": "0.35",
- "linestyle": "solid",
- "linewidth": 1,
- "marker": "o",
- "markersize": 3
- },
- "subsets": [
- "Subset 1_0",
- "Subset 2_0"
- ],
- "uuid": "dde080dc-a65a-4988-bed9-c0cb90ff91a8"
- },
- "c": {
- "_type": "glue.core.component_id.ComponentID",
- "hidden": false,
- "label": "c"
- }
-}
\ No newline at end of file
diff --git a/glue/viewers/scatter/qt/tests/test_data_viewer.py b/glue/viewers/scatter/qt/tests/test_data_viewer.py
deleted file mode 100644
index c0452d098..000000000
--- a/glue/viewers/scatter/qt/tests/test_data_viewer.py
+++ /dev/null
@@ -1,1004 +0,0 @@
-# pylint: disable=I0011,W0613,W0201,W0212,E1101,E1103
-
-import os
-from collections import Counter
-
-import pytest
-import numpy as np
-
-from numpy.testing import assert_allclose, assert_equal
-
-from glue.config import colormaps
-from glue.core.message import SubsetUpdateMessage
-from glue.core import HubListener, Data
-from glue.core.roi import XRangeROI, RectangularROI, CircularROI
-from glue.core.roi_pretransforms import FullSphereLongitudeTransform, ProjectionMplTransform, RadianTransform
-from glue.core.subset import RoiSubsetState, AndState
-from glue import core
-from glue.core.component_id import ComponentID
-from glue.utils.qt import combo_as_string, process_events
-from glue.viewers.matplotlib.qt.tests.test_data_viewer import BaseTestMatplotlibDataViewer
-from glue.core.state import GlueUnSerializer
-from glue.app.qt.layer_tree_widget import LayerTreeWidget
-from glue.app.qt import GlueApplication
-
-from ..data_viewer import ScatterViewer
-
-DATA = os.path.join(os.path.dirname(__file__), 'data')
-
-fullsphere_projections = ['aitoff', 'hammer', 'lambert', 'mollweide']
-
-
-class TestScatterCommon(BaseTestMatplotlibDataViewer):
- def init_data(self):
- return Data(label='d1', x=[3.4, 2.3, -1.1, 0.3], y=['a', 'b', 'c', 'a'])
- viewer_cls = ScatterViewer
-
-
-class TestScatterViewer(object):
-
- def setup_method(self, method):
-
- self.data = Data(label='d1', x=[3.4, 2.3, -1.1, 0.3],
- y=[3.2, 3.3, 3.4, 3.5], z=['a', 'b', 'c', 'a'])
- self.data_2d = Data(label='d2', a=[[1, 2], [3, 4]], b=[[5, 6], [7, 8]],
- x=[[3, 5], [5.4, 1]], y=[[1.2, 4], [7, 8]])
- self.data_fullsphere = Data(label='d3', x=[6.9, -1.1, 1.2, -3.7],
- y=[-0.2, 1.0, 0.5, -1.1])
-
- self.app = GlueApplication()
- self.session = self.app.session
- self.hub = self.session.hub
-
- self.data_collection = self.session.data_collection
- self.data_collection.append(self.data)
- self.data_collection.append(self.data_2d)
- self.data_collection.append(self.data_fullsphere)
-
- self.viewer = self.app.new_data_viewer(ScatterViewer)
-
- def teardown_method(self, method):
- self.viewer.close()
- self.viewer = None
- self.app.close()
- self.app = None
-
- def test_basic(self):
-
- viewer_state = self.viewer.state
-
- # Check defaults when we add data
- self.viewer.add_data(self.data)
-
- assert combo_as_string(self.viewer.options_widget().ui.combosel_x_att) == 'Main components:x:y:z:Coordinate components:Pixel Axis 0 [x]'
- assert combo_as_string(self.viewer.options_widget().ui.combosel_y_att) == 'Main components:x:y:z:Coordinate components:Pixel Axis 0 [x]'
-
- assert viewer_state.x_att is self.data.id['x']
- assert_allclose(viewer_state.x_min, -1.1 - 0.18)
- assert_allclose(viewer_state.x_max, 3.4 + 0.18)
-
- assert viewer_state.y_att is self.data.id['y']
- assert_allclose(viewer_state.y_min, 3.2 - 0.012)
- assert_allclose(viewer_state.y_max, 3.5 + 0.012)
-
- assert not viewer_state.x_log
- assert not viewer_state.y_log
-
- assert len(viewer_state.layers) == 1
-
- # Change to categorical component and check new values
-
- viewer_state.y_att = self.data.id['z']
-
- assert viewer_state.x_att is self.data.id['x']
- assert_allclose(viewer_state.x_min, -1.1 - 0.18)
- assert_allclose(viewer_state.x_max, 3.4 + 0.18)
-
- assert viewer_state.y_att is self.data.id['z']
- assert_allclose(viewer_state.y_min, -0.5 - 0.12)
- assert_allclose(viewer_state.y_max, 2.5 + 0.12)
-
- assert not viewer_state.x_log
- assert not viewer_state.y_log
-
- def test_flip(self):
-
- viewer_state = self.viewer.state
-
- self.viewer.add_data(self.data)
-
- assert_allclose(viewer_state.x_min, -1.1 - 0.18)
- assert_allclose(viewer_state.x_max, 3.4 + 0.18)
-
- self.viewer.options_widget().button_flip_x.click()
-
- assert_allclose(viewer_state.x_max, -1.1 - 0.18)
- assert_allclose(viewer_state.x_min, 3.4 + 0.18)
-
- assert_allclose(viewer_state.y_min, 3.2 - 0.012)
- assert_allclose(viewer_state.y_max, 3.5 + 0.012)
-
- self.viewer.options_widget().button_flip_y.click()
-
- assert_allclose(viewer_state.y_max, 3.2 - 0.012)
- assert_allclose(viewer_state.y_min, 3.5 + 0.012)
-
- def test_remove_data(self):
- self.viewer.add_data(self.data)
- assert combo_as_string(self.viewer.options_widget().ui.combosel_x_att) == 'Main components:x:y:z:Coordinate components:Pixel Axis 0 [x]'
- assert combo_as_string(self.viewer.options_widget().ui.combosel_y_att) == 'Main components:x:y:z:Coordinate components:Pixel Axis 0 [x]'
- self.data_collection.remove(self.data)
- assert combo_as_string(self.viewer.options_widget().ui.combosel_x_att) == ''
- assert combo_as_string(self.viewer.options_widget().ui.combosel_y_att) == ''
-
- def test_update_component_updates_title(self):
- self.viewer.add_data(self.data)
- assert self.viewer.windowTitle() == '2D Scatter'
- self.viewer.state.x_att = self.data.id['y']
- assert self.viewer.windowTitle() == '2D Scatter'
-
- def test_combo_updates_with_component_add(self):
- self.viewer.add_data(self.data)
- self.data.add_component([3, 4, 1, 2], 'a')
- assert self.viewer.state.x_att is self.data.id['x']
- assert self.viewer.state.y_att is self.data.id['y']
- assert combo_as_string(self.viewer.options_widget().ui.combosel_x_att) == 'Main components:x:y:z:a:Coordinate components:Pixel Axis 0 [x]'
- assert combo_as_string(self.viewer.options_widget().ui.combosel_y_att) == 'Main components:x:y:z:a:Coordinate components:Pixel Axis 0 [x]'
-
- def test_nonnumeric_first_component(self):
- # regression test for #208. Shouldn't complain if
- # first component is non-numerical
- data = core.Data()
- data.add_component(['a', 'b', 'c'], label='c1')
- data.add_component([1, 2, 3], label='c2')
- self.data_collection.append(data)
- self.viewer.add_data(data)
-
- def test_apply_roi(self):
-
- self.viewer.add_data(self.data)
-
- roi = RectangularROI(0, 3, 3.25, 3.45)
-
- assert len(self.viewer.layers) == 1
-
- self.viewer.apply_roi(roi)
-
- assert len(self.viewer.layers) == 2
- assert len(self.data.subsets) == 1
-
- assert_allclose(self.data.subsets[0].to_mask(), [0, 1, 0, 0])
-
- state = self.data.subsets[0].subset_state
- assert isinstance(state, RoiSubsetState)
-
- def test_apply_roi_categorical(self):
-
- viewer_state = self.viewer.state
-
- self.viewer.add_data(self.data)
-
- viewer_state.y_att = self.data.id['z']
-
- roi = RectangularROI(0, 3, -0.4, 0.3)
-
- assert len(self.viewer.layers) == 1
-
- self.viewer.apply_roi(roi)
-
- assert len(self.viewer.layers) == 2
- assert len(self.data.subsets) == 1
-
- assert_allclose(self.data.subsets[0].to_mask(), [0, 0, 0, 1])
-
- state = self.data.subsets[0].subset_state
- assert isinstance(state, AndState)
-
- def test_apply_roi_empty(self):
- # Make sure that doing an ROI selection on an empty viewer doesn't
- # produce error messsages
- roi = XRangeROI(-0.2, 0.1)
- self.viewer.apply_roi(roi)
-
- def test_axes_labels(self):
-
- viewer_state = self.viewer.state
-
- self.viewer.add_data(self.data)
-
- assert self.viewer.axes.get_xlabel() == 'x'
- assert self.viewer.axes.get_ylabel() == 'y'
-
- viewer_state.x_log = True
-
- assert self.viewer.axes.get_xlabel() == 'x'
- assert self.viewer.axes.get_ylabel() == 'y'
-
- viewer_state.x_att = self.data.id['y']
-
- assert self.viewer.axes.get_xlabel() == 'y'
- assert self.viewer.axes.get_ylabel() == 'y'
-
- viewer_state.y_log = True
-
- assert self.viewer.axes.get_xlabel() == 'y'
- assert self.viewer.axes.get_ylabel() == 'y'
-
- def test_component_replaced(self):
-
- # regression test for 508 - if a component ID is replaced, we should
- # make sure that the component ID is selected if the old component ID
- # was selected
-
- self.viewer.add_data(self.data)
- self.viewer.state.x_att = self.data.id['x']
- test = ComponentID('test')
- self.data.update_id(self.viewer.state.x_att, test)
- assert self.viewer.state.x_att is test
- assert combo_as_string(self.viewer.options_widget().ui.combosel_x_att) == 'Main components:test:y:z:Coordinate components:Pixel Axis 0 [x]'
-
- def test_nan_component(self):
- # regression test for case when all values are NaN in a component
- data = core.Data()
- data.add_component([np.nan, np.nan, np.nan], label='c1')
- self.data_collection.append(data)
- self.viewer.add_data(data)
-
- def test_density_map(self):
-
- kwargs = dict(range=[(-5, 5), (-5, 5)], bins=(2, 2))
-
- self.viewer.add_data(self.data)
- self.viewer.state.layers[0].points_mode = 'auto'
- assert self.viewer.layers[0].state.compute_density_map(**kwargs).sum() == 0
- self.viewer.state.layers[0].points_mode = 'density'
- assert self.viewer.layers[0].state.compute_density_map(**kwargs).sum() == 4
- self.viewer.state.layers[0].points_mode = 'markers'
- assert self.viewer.layers[0].state.compute_density_map(**kwargs).sum() == 0
-
- def test_density_map_color(self):
-
- # Regression test to make sure things don't crash when changing
- # back to markers if the color mode is cmap
-
- self.viewer.add_data(self.data)
- self.viewer.state.layers[0].points_mode = 'density'
- self.viewer.state.layers[0].cmap_mode = 'Linear'
- self.viewer.state.layers[0].size_mode = 'Linear'
- self.viewer.state.layers[0].points_mode = 'markers'
- self.viewer.state.layers[0].points_mode = 'density'
-
- @pytest.mark.parametrize('protocol', [0, 1])
- def test_session_back_compat(self, protocol):
-
- filename = os.path.join(DATA, 'scatter_v{0}.glu'.format(protocol))
-
- with open(filename, 'r') as f:
- session = f.read()
-
- state = GlueUnSerializer.loads(session)
-
- ga = state.object('__main__')
-
- dc = ga.session.data_collection
-
- assert len(dc) == 1
-
- assert dc[0].label == 'basic'
-
- viewer1 = ga.viewers[0][0]
- assert len(viewer1.state.layers) == 3
- assert viewer1.state.x_att is dc[0].id['a']
- assert viewer1.state.y_att is dc[0].id['b']
- assert_allclose(viewer1.state.x_min, -1.04)
- assert_allclose(viewer1.state.x_max, 1.04)
- assert_allclose(viewer1.state.y_min, 1.98)
- assert_allclose(viewer1.state.y_max, 3.02)
- assert not viewer1.state.x_log
- assert not viewer1.state.y_log
- assert viewer1.state.layers[0].visible
- assert viewer1.state.layers[1].visible
- assert viewer1.state.layers[2].visible
-
- viewer2 = ga.viewers[0][1]
- assert len(viewer2.state.layers) == 3
- assert viewer2.state.x_att is dc[0].id['a']
- assert viewer2.state.y_att is dc[0].id['c']
- assert_allclose(viewer2.state.x_min, 9.5e-6)
- assert_allclose(viewer2.state.x_max, 1.05)
- assert_allclose(viewer2.state.y_min, 0.38)
- assert_allclose(viewer2.state.y_max, 5.25)
- assert viewer2.state.x_log
- assert viewer2.state.y_log
- assert viewer2.state.layers[0].visible
- assert not viewer2.state.layers[1].visible
- assert viewer2.state.layers[2].visible
-
- viewer3 = ga.viewers[0][2]
- assert len(viewer3.state.layers) == 3
- assert viewer3.state.x_att is dc[0].id['b']
- assert viewer3.state.y_att is dc[0].id['a']
- assert_allclose(viewer3.state.x_min, 0)
- assert_allclose(viewer3.state.x_max, 5)
- assert_allclose(viewer3.state.y_min, -5)
- assert_allclose(viewer3.state.y_max, 5)
- assert not viewer3.state.x_log
- assert not viewer3.state.y_log
- assert viewer3.state.layers[0].visible
- assert viewer3.state.layers[1].visible
- assert not viewer3.state.layers[2].visible
-
- ga.close()
-
- def test_session_line_back_compat(self):
-
- # Backward-compatibility for v0.11 files in which the line and scatter
- # plots were defined as separate styles.
-
- filename = os.path.join(DATA, 'scatter_and_line_v1.glu')
-
- with open(filename, 'r') as f:
- session = f.read()
-
- state = GlueUnSerializer.loads(session)
-
- ga = state.object('__main__')
-
- dc = ga.session.data_collection
-
- assert len(dc) == 1
-
- assert dc[0].label == 'table'
-
- viewer1 = ga.viewers[0][0]
- assert len(viewer1.state.layers) == 1
- assert viewer1.state.x_att is dc[0].id['a']
- assert viewer1.state.y_att is dc[0].id['b']
- assert viewer1.state.layers[0].markers_visible
- assert not viewer1.state.layers[0].line_visible
-
- viewer1 = ga.viewers[0][1]
- assert len(viewer1.state.layers) == 1
- assert viewer1.state.x_att is dc[0].id['a']
- assert viewer1.state.y_att is dc[0].id['b']
- assert not viewer1.state.layers[0].markers_visible
- assert viewer1.state.layers[0].line_visible
-
- ga.close()
-
- def test_save_svg(self, tmpdir):
- # Regression test for a bug in AxesCache that caused SVG saving to
- # fail (because renderer.buffer_rgba did not exist)
- self.viewer.add_data(self.data)
- filename = tmpdir.join('test.svg').strpath
- self.viewer.axes.figure.savefig(filename)
-
- def test_2d(self):
-
- viewer_state = self.viewer.state
-
- self.viewer.add_data(self.data_2d)
-
- assert viewer_state.x_att is self.data_2d.id['a']
- assert_allclose(viewer_state.x_min, 1 - 0.12)
- assert_allclose(viewer_state.x_max, 4 + 0.12)
-
- assert viewer_state.y_att is self.data_2d.id['b']
- assert_allclose(viewer_state.y_min, 5 - 0.12)
- assert_allclose(viewer_state.y_max, 8 + 0.12)
-
- assert self.viewer.layers[0].plot_artist.get_xdata().shape == (4,)
-
- def test_apply_roi_single(self):
-
- # Regression test for a bug that caused mode.update to be called
- # multiple times and resulted in all other viewers receiving many
- # messages regarding subset updates (this occurred when multiple)
- # datasets were present.
-
- layer_tree = LayerTreeWidget(session=self.session)
- layer_tree.set_checkable(False)
- layer_tree.setup(self.data_collection)
- layer_tree.bind_selection_to_edit_subset()
-
- class Client(HubListener):
-
- def __init__(self, *args, **kwargs):
- super(Client, self).__init__(*args, **kwargs)
- self.count = Counter()
-
- def ping(self, message):
- self.count[message.sender] += 1
-
- def register_to_hub(self, hub):
- hub.subscribe(self, SubsetUpdateMessage, handler=self.ping)
-
- d1 = Data(a=[1, 2, 3], label='d3')
- d2 = Data(b=[1, 2, 3], label='d4')
- d3 = Data(c=[1, 2, 3], label='d5')
- d4 = Data(d=[1, 2, 3], label='d6')
-
- self.data_collection.append(d1)
- self.data_collection.append(d2)
- self.data_collection.append(d3)
- self.data_collection.append(d4)
-
- client = Client()
- client.register_to_hub(self.hub)
-
- self.viewer.add_data(d1)
- self.viewer.add_data(d3)
-
- roi = XRangeROI(2.5, 3.5)
- self.viewer.apply_roi(roi)
-
- for subset in client.count:
- assert client.count[subset] == 1
-
- @pytest.mark.parametrize('ndim', [1, 2])
- def test_all_options(self, ndim):
-
- # This test makes sure that all the code for the different scatter modes
- # gets run, though does not check the result.
-
- viewer_state = self.viewer.state
-
- if ndim == 1:
- data = self.data
- elif ndim == 2:
- data = self.data_2d
-
- self.viewer.add_data(data)
-
- layer_state = viewer_state.layers[0]
-
- layer_state.style = 'Scatter'
-
- layer_state.size_mode = 'Linear'
- layer_state.size_att = data.id['y']
- layer_state.size_vmin = 1.2
- layer_state.size_vmax = 4.
- layer_state.size_scaling = 2
-
- layer_state.cmap_mode = 'Linear'
- layer_state.cmap_att = data.id['x']
- layer_state.cmap_vmin = -1
- layer_state.cmap_vmax = 2.
- layer_state.cmap = colormaps.members[3][1]
-
- # Check inverting works
- layer_state.cmap_vmin = 3.
-
- layer_state.size_mode = 'Fixed'
-
- layer_state.xerr_visible = True
- layer_state.xerr_att = data.id['x']
- layer_state.yerr_visible = True
- layer_state.yerr_att = data.id['y']
-
- layer_state.style = 'Line'
- layer_state.linewidth = 3
- layer_state.linestyle = 'dashed'
-
- def test_session_categorical(self, tmpdir):
-
- def visible_xaxis_labels(ax):
- # Due to a bug in Matplotlib the labels returned outside the field
- # of view may be incorrect: https://github.com/matplotlib/matplotlib/issues/9397
- pos = ax.xaxis.get_ticklocs()
- labels = [tick.get_text() for tick in ax.xaxis.get_ticklabels()]
- xmin, xmax = ax.get_xlim()
- return [labels[i] for i in range(len(pos)) if pos[i] >= xmin and pos[i] <= xmax]
-
- # Regression test for a bug that caused a restored scatter viewer
- # with a categorical component to not show the categorical labels
- # as tick labels.
-
- filename = tmpdir.join('test_session_categorical.glu').strpath
-
- self.viewer.add_data(self.data)
- self.viewer.state.x_att = self.data.id['z']
-
- process_events()
-
- assert visible_xaxis_labels(self.viewer.axes) == ['a', 'b', 'c']
-
- self.session.application.save_session(filename)
-
- with open(filename, 'r') as f:
- session = f.read()
-
- state = GlueUnSerializer.loads(session)
-
- ga = state.object('__main__')
-
- dc = ga.session.data_collection
-
- viewer = ga.viewers[0][0]
- assert viewer.state.x_att is dc[0].id['z']
- assert visible_xaxis_labels(self.viewer.axes) == ['a', 'b', 'c']
-
- ga.close()
-
- def test_enable_disable_components_combo(self):
-
- # Regression test for a bug that caused an error when turning off pixel
- # components from combo boxes.
-
- self.viewer.add_data(self.data)
-
- self.data['a'] = self.data.id['x'] + 5
-
- self.viewer.state.x_att_helper.pixel_coord = True
-
- self.viewer.state.x_att = self.data.pixel_component_ids[0]
-
- self.viewer.state.x_att_helper.pixel_coord = False
-
- def test_datetime64_support(self, tmpdir):
-
- self.data.add_component(np.array([100, 200, 300, 400], dtype='M8[D]'), 't1')
- self.data.add_component(np.array([200, 300, 400, 500], dtype='M8[D]'), 't2')
- self.viewer.add_data(self.data)
- self.viewer.state.x_att = self.data.id['t1']
- self.viewer.state.y_att = self.data.id['y']
-
- # Matplotlib deals with dates by converting them to the number of days
- # since 01-01-0001, so we can check that the limits are correctly
- # converted (and not 100 to 400)
- assert self.viewer.axes.get_xlim() == (719251.0, 719575.0)
- assert self.viewer.axes.get_ylim() == (3.2 - 0.012, 3.5 + 0.012)
-
- # Apply an ROI selection in plotting coordinates
- roi = RectangularROI(xmin=719313, xmax=719513, ymin=3, ymax=4)
- self.viewer.apply_roi(roi)
-
- # Check that the two middle elements are selected
- assert_equal(self.data.subsets[0].to_mask(), [0, 1, 1, 0])
-
- # Now do the same with the y axis
- self.viewer.state.y_att = self.data.id['t2']
-
- assert self.viewer.axes.get_xlim() == (719251.0, 719575.0)
- assert self.viewer.axes.get_ylim() == (719351.0, 719675.0)
-
- # Apply an ROI selection in plotting coordinates
- edit = self.session.edit_subset_mode
- edit.edit_subset = []
- roi = CircularROI(xc=719463, yc=719563, radius=200)
- self.viewer.apply_roi(roi)
- assert_equal(self.data.subsets[1].to_mask(), [0, 1, 1, 1])
-
- # Make sure that the Qt labels look ok
- self.viewer.state.y_att = self.data.id['y']
- options = self.viewer.options_widget().ui
- assert options.valuetext_x_min.text() == '1970-03-30'
- assert options.valuetext_x_max.text() == '1971-02-17'
- assert options.valuetext_y_min.text() == '3.188'
- assert options.valuetext_y_max.text() == '3.512'
-
- # Make sure that we can set the xmin/xmax to a string date
- assert_equal(self.viewer.state.x_min, np.datetime64('1970-03-30', 'D'))
- options.valuetext_x_min.setText('1970-04-14')
- options.valuetext_x_min.editingFinished.emit()
- assert self.viewer.axes.get_xlim() == (719266.0, 719575.0)
- assert_equal(self.viewer.state.x_min, np.datetime64('1970-04-14', 'D'))
-
- # Make sure that everything works fine after saving/reloading
- filename = tmpdir.join('test_datetime64.glu').strpath
- self.session.application.save_session(filename)
- with open(filename, 'r') as f:
- session = f.read()
- state = GlueUnSerializer.loads(session)
- ga = state.object('__main__')
- viewer = ga.viewers[0][0]
- options = viewer.options_widget().ui
-
- assert_equal(self.viewer.state.x_min, np.datetime64('1970-04-14', 'D'))
-
- assert options.valuetext_x_min.text() == '1970-04-14'
- assert options.valuetext_x_max.text() == '1971-02-17'
- assert options.valuetext_y_min.text() == '3.188'
- assert options.valuetext_y_max.text() == '3.512'
-
- ga.close()
-
- def test_datetime64_disabled(self, capsys):
-
- # Make sure that datetime components aren't options for the vector and
- # error markers.
-
- data = Data(label='test')
- data.add_component(np.array([100, 200, 300, 400], dtype='M8[D]'), 't1')
- data.add_component(np.array([200, 300, 400, 500], dtype='M8[D]'), 't2')
- data.add_component(np.array([200., 300., 400., 500.]), 'x')
- data.add_component(np.array([200., 300., 400., 500.]), 'y')
- self.data_collection.append(data)
-
- self.viewer.add_data(data)
- self.viewer.state.x_att = data.id['x']
- self.viewer.state.y_att = data.id['y']
- self.viewer.state.layers[0].cmap_mode = 'Linear'
- self.viewer.state.layers[0].cmap_att = data.id['x']
- self.viewer.state.layers[0].size_mode = 'Linear'
- self.viewer.state.layers[0].size_att = data.id['y']
- self.viewer.state.layers[0].vector_visible = True
- self.viewer.state.layers[0].xerr_visible = True
- self.viewer.state.layers[0].yerr_visible = True
-
- process_events()
-
- self.viewer.state.x_att = data.id['t1']
- self.viewer.state.y_att = data.id['t2']
-
- process_events()
-
- # We use capsys here because the # error is otherwise only apparent in stderr.
- out, err = capsys.readouterr()
- assert out.strip() == ""
- assert err.strip() == ""
-
- def test_density_map_incompatible_subset(self, capsys):
-
- # Regression test for a bug that caused the scatter viewer to crash
- # if subset for density map was incompatible.
-
- data2 = Data(label='d1', x=[3.4, 2.3, -1.1, 0.3], y=[3.2, 3.3, 3.4, 3.5], z=['a', 'b', 'c', 'a'])
-
- self.data_collection.append(data2)
-
- self.viewer.add_data(self.data)
- self.viewer.add_data(data2)
-
- self.data_collection.new_subset_group('test', self.data.id['x'] > 1)
-
- for layer in self.viewer.state.layers:
- layer.density_map = True
-
- self.viewer.figure.canvas.draw()
- process_events()
-
- assert self.viewer.layers[0].enabled
- assert not self.viewer.layers[1].enabled
- assert self.viewer.layers[2].enabled
- assert not self.viewer.layers[3].enabled
-
- def test_density_map_line_error_vector(self, capsys):
-
- # Make sure that we don't allow/show lines/errors/vectors
- # if in density map mode.
-
- self.viewer.add_data(self.data)
-
- self.viewer.state.layers[0].line_visible = True
- self.viewer.state.layers[0].xerr_visible = True
- self.viewer.state.layers[0].yerr_visible = True
- self.viewer.state.layers[0].vector_visible = True
-
- # Setting density_map to True resets the visibility of
- # lines/errors/vectors.
- self.viewer.state.layers[0].density_map = True
- assert not self.viewer.state.layers[0].line_visible
- assert not self.viewer.state.layers[0].xerr_visible
- assert not self.viewer.state.layers[0].yerr_visible
- assert not self.viewer.state.layers[0].vector_visible
-
- def test_legend(self):
- viewer_state = self.viewer.state
-
- self.viewer.add_data(self.data)
- viewer_state.legend.visible = True
-
- handles, labels, handler_dict = self.viewer.get_handles_legend()
- assert len(handles) == 1
- assert labels[0] == 'd1'
-
- self.data_collection.new_subset_group('test', self.data.id['x'] > 1)
- assert len(viewer_state.layers) == 2
- handles, labels, handler_dict = self.viewer.get_handles_legend()
-
- assert len(handles) == 2
- assert labels[1] == 'test'
- print(handles[1][0])
- # assert handles[1][0].get_color() == viewer_state.layers[1].state.color
-
- # Add a non visible layer
- data2 = Data(label='d2', x=[3.4, 2.3, -1.1, 0.3], y=[3.2, 3.3, 3.4, 3.5])
- self.data_collection.append(data2)
-
- self.viewer.add_data(data2)
- assert len(viewer_state.layers) == 4
-
- # 'd2' is not enabled (no linked component)
- handles, labels, handler_dict = self.viewer.get_handles_legend()
- assert len(handles) == 2
-
- def test_changing_plot_modes(self):
- viewer_state = self.viewer.state
- viewer_state.plot_mode = 'polar'
- assert 'polar' in str(type(self.viewer.axes)).lower()
- viewer_state.plot_mode = 'aitoff'
- assert 'aitoff' in str(type(self.viewer.axes)).lower()
- viewer_state.plot_mode = 'hammer'
- assert 'hammer' in str(type(self.viewer.axes)).lower()
- viewer_state.plot_mode = 'lambert'
- assert 'lambert' in str(type(self.viewer.axes)).lower()
- viewer_state.plot_mode = 'mollweide'
- assert 'mollweide' in str(type(self.viewer.axes)).lower()
-
- # For the time being, the polar plots don't support log scaling
- # def test_limit_log_set_polar(self):
- # self.viewer.add_data(self.data)
- # viewer_state = self.viewer.state
- # viewer_state.plot_mode = "polar"
- # axes = self.viewer.axes
- #
- # viewer_state.x_min = 0.5
- # viewer_state.x_max = 1.5
- # assert_allclose(axes.get_xlim(), [0.5, 1.5])
- #
- # viewer_state.y_min = -2.5
- # viewer_state.y_max = 2.5
- # assert_allclose(axes.get_ylim(), [-2.5, 2.5])
- #
- # viewer_state.y_log = True
- # assert axes.get_yscale() == 'log'
-
- def test_limit_set_fullsphere(self):
- # Make sure that the full-sphere projections ignore instead of throwing exceptions
- self.viewer.add_data(self.data)
- viewer_state = self.viewer.state
-
- for proj in fullsphere_projections:
- viewer_state.plot_mode = proj
- error_msg = 'Issue with {} projection'.format(proj)
- axes = self.viewer.axes
- viewer_state.x_min = 0.5
- viewer_state.x_max = 1.5
- viewer_state.y_min = -2.5
- viewer_state.y_max = 2.5
- assert_allclose(axes.get_xlim(), [-np.pi, np.pi], err_msg=error_msg)
- assert_allclose(axes.get_ylim(), [-np.pi / 2, np.pi / 2], err_msg=error_msg)
-
- def test_changing_mode_limits(self):
- self.viewer.add_data(self.data)
- viewer_state = self.viewer.state
- old_xmin = viewer_state.x_min
- old_xmax = viewer_state.x_max
- old_ymin = viewer_state.y_min
- old_ymax = viewer_state.y_max
- # Make sure limits are reset first
- viewer_state.x_max += 3
-
- # Currently, when we change to polar mode, the x-limits are changed to 0, 2pi
- viewer_state.plot_mode = 'polar'
- assert_allclose(viewer_state.x_min, 0)
- assert_allclose(viewer_state.x_max, 2 * np.pi)
- assert_allclose(self.viewer.axes.get_xlim(), [0, 2 * np.pi])
- assert_allclose(viewer_state.y_min, old_ymin)
- assert_allclose(viewer_state.y_max, old_ymax)
- assert_allclose(self.viewer.axes.get_ylim(), [old_ymin, old_ymax])
-
- viewer_state.plot_mode = 'rectilinear'
- assert_allclose(viewer_state.x_min, old_xmin)
- assert_allclose(viewer_state.x_max, old_xmax)
- assert_allclose(self.viewer.axes.get_xlim(), [old_xmin, old_xmax])
- assert_allclose(viewer_state.y_min, old_ymin)
- assert_allclose(viewer_state.y_max, old_ymax)
- assert_allclose(self.viewer.axes.get_ylim(), [old_ymin, old_ymax])
-
- for proj in fullsphere_projections:
- viewer_state.plot_mode = 'rectilinear'
- viewer_state.plot_mode = proj
- error_msg = 'Issue with {} projection'.format(proj)
- assert_allclose(viewer_state.x_min, -np.pi)
- assert_allclose(viewer_state.x_max, np.pi)
- assert_allclose(self.viewer.axes.get_xlim(), [-np.pi, np.pi], err_msg=error_msg)
- assert_allclose(viewer_state.y_min, -np.pi / 2)
- assert_allclose(viewer_state.y_max, np.pi / 2)
- assert_allclose(self.viewer.axes.get_ylim(), [-np.pi / 2, np.pi / 2], err_msg=error_msg)
-
- def test_changing_mode_log(self):
- # Test to make sure we reset the log axes to false when changing modes to prevent problems
- self.viewer.add_data(self.data)
- viewer_state = self.viewer.state
- viewer_state.x_log = True
- viewer_state.y_log = True
-
- viewer_state.plot_mode = 'polar'
- assert not viewer_state.x_log
- assert not viewer_state.y_log
- assert self.viewer.axes.get_xscale() == 'linear'
- assert self.viewer.axes.get_yscale() == 'linear'
- viewer_state.y_log = True
-
- viewer_state.plot_mode = 'rectilinear'
- assert not viewer_state.x_log
- assert not viewer_state.y_log
- assert self.viewer.axes.get_xscale() == 'linear'
- assert self.viewer.axes.get_yscale() == 'linear'
-
- for proj in fullsphere_projections:
- viewer_state.plot_mode = 'rectilinear'
- viewer_state.x_log = True
- viewer_state.y_log = True
- viewer_state.plot_mode = proj
- error_msg = 'Issue with {} projection'.format(proj)
- assert not viewer_state.x_log, error_msg
- assert not viewer_state.y_log, error_msg
- assert self.viewer.axes.get_xscale() == 'linear', error_msg
- assert self.viewer.axes.get_yscale() == 'linear', error_msg
-
- def test_full_circle_utility(self):
- # Make sure that the full circle function behaves well
- self.viewer.add_data(self.data)
- viewer_state = self.viewer.state
- old_xmin = viewer_state.x_min
- old_xmax = viewer_state.x_max
- old_ymin = viewer_state.y_min
- old_ymax = viewer_state.y_max
- viewer_state.full_circle()
- assert_allclose([viewer_state.x_min, viewer_state.x_max], [old_xmin, old_xmax])
- assert_allclose([viewer_state.y_min, viewer_state.y_max], [old_ymin, old_ymax])
-
- viewer_state.plot_mode = 'polar'
- viewer_state.full_circle()
- assert_allclose([viewer_state.x_min, viewer_state.x_max], [0, 2 * np.pi])
- assert_allclose([viewer_state.y_min, viewer_state.y_max], [old_ymin, old_ymax])
-
- for proj in fullsphere_projections:
- error_msg = 'Issue with {} projection'.format(proj)
- viewer_state.plot_mode = proj
- viewer_state.full_circle()
- assert_allclose([viewer_state.x_min, viewer_state.x_max], [-np.pi, np.pi], err_msg=error_msg)
- assert_allclose([viewer_state.y_min, viewer_state.y_max], [-np.pi / 2, np.pi / 2], err_msg=error_msg)
-
- def test_limits_log_widget_polar_cartesian(self):
- ui = self.viewer.options_widget().ui
- viewer_state = self.viewer.state
- viewer_state.plot_mode = 'polar'
- assert not ui.bool_x_log.isEnabled()
- assert not ui.bool_x_log_.isEnabled()
- assert not ui.bool_y_log.isEnabled()
- assert not ui.bool_y_log_.isEnabled()
- assert ui.valuetext_x_min.isEnabled()
- assert ui.button_flip_x.isEnabled()
- assert ui.valuetext_x_max.isEnabled()
- assert ui.valuetext_y_min.isEnabled()
- assert ui.button_flip_y.isEnabled()
- assert ui.valuetext_y_max.isEnabled()
- assert ui.button_full_circle.isHidden()
-
- viewer_state.plot_mode = 'rectilinear'
- assert ui.bool_x_log.isEnabled()
- assert ui.bool_x_log_.isEnabled()
- assert ui.bool_y_log.isEnabled()
- assert ui.bool_y_log_.isEnabled()
- assert ui.valuetext_x_min.isEnabled()
- assert ui.button_flip_x.isEnabled()
- assert ui.valuetext_x_max.isEnabled()
- assert ui.valuetext_y_min.isEnabled()
- assert ui.button_flip_y.isEnabled()
- assert ui.valuetext_y_max.isEnabled()
- assert ui.button_full_circle.isHidden()
- assert ui.button_full_circle.isHidden()
-
- def test_limits_log_widget_fullsphere(self):
- ui = self.viewer.options_widget().ui
- viewer_state = self.viewer.state
- for proj in fullsphere_projections:
- error_msg = 'Issue with {} projection'.format(proj)
- viewer_state.plot_mode = proj
- not ui.bool_x_log.isEnabled()
- assert not ui.bool_x_log_.isEnabled(), error_msg
- assert not ui.bool_y_log.isEnabled(), error_msg
- assert not ui.bool_y_log_.isEnabled(), error_msg
- assert not ui.valuetext_x_min.isEnabled(), error_msg
- assert ui.button_flip_x.isEnabled(), error_msg
- assert not ui.valuetext_x_max.isEnabled(), error_msg
- assert not ui.valuetext_y_min.isEnabled(), error_msg
- assert ui.button_flip_y.isEnabled(), error_msg
- assert not ui.valuetext_y_max.isEnabled(), error_msg
- assert ui.button_full_circle.isHidden(), error_msg
-
- viewer_state.plot_mode = 'rectilinear'
- assert ui.bool_x_log.isEnabled()
- assert ui.bool_x_log_.isEnabled()
- assert ui.bool_y_log.isEnabled()
- assert ui.bool_y_log_.isEnabled()
- assert ui.valuetext_x_min.isEnabled()
- assert ui.button_flip_x.isEnabled()
- assert ui.valuetext_x_max.isEnabled()
- assert ui.valuetext_y_min.isEnabled()
- assert ui.button_flip_y.isEnabled()
- assert ui.valuetext_y_max.isEnabled()
- assert ui.button_full_circle.isHidden()
-
- @pytest.mark.parametrize('angle_unit,expected_mask', [('radians', [0, 0, 0, 1]), ('degrees', [1, 1, 0, 1])])
- def test_apply_roi_polar(self, angle_unit, expected_mask):
- self.viewer.add_data(self.data)
- viewer_state = self.viewer.state
- roi = RectangularROI(0.5, 1, 0.5, 1)
- viewer_state.plot_mode = 'polar'
- viewer_state.full_circle()
- assert len(self.viewer.layers) == 1
-
- viewer_state.angle_unit = angle_unit
-
- self.viewer.apply_roi(roi)
-
- assert len(self.viewer.layers) == 2
- assert len(self.data.subsets) == 1
-
- assert_allclose(self.data.subsets[0].to_mask(), expected_mask)
-
- state = self.data.subsets[0].subset_state
- assert isinstance(state, RoiSubsetState)
- assert state.pretransform
- pretrans = state.pretransform
- if angle_unit == 'radians':
- assert isinstance(pretrans, ProjectionMplTransform)
- projtrans = pretrans
- elif angle_unit == 'degrees':
- assert isinstance(pretrans, RadianTransform)
- projtrans = pretrans._next_transform
- assert isinstance(projtrans, ProjectionMplTransform)
- assert projtrans._state['projection'] == 'polar'
- assert_allclose(projtrans._state['x_lim'], [viewer_state.x_min, viewer_state.x_max])
- assert_allclose(projtrans._state['y_lim'], [viewer_state.y_min, viewer_state.y_max])
- assert projtrans._state['x_scale'] == 'linear'
- assert projtrans._state['y_scale'] == 'linear'
- self.data.subsets[0].delete()
-
- viewer_state.y_log = True
- self.viewer.apply_roi(roi)
- state = self.data.subsets[0].subset_state
- assert state.pretransform
- pretrans = state.pretransform
- if angle_unit == 'radians':
- assert isinstance(pretrans, ProjectionMplTransform)
- projtrans = pretrans
- elif angle_unit == 'degrees':
- assert isinstance(pretrans, RadianTransform)
- projtrans = pretrans._next_transform
- assert isinstance(projtrans, ProjectionMplTransform)
- assert projtrans._state['y_scale'] == 'log'
- viewer_state.y_log = False
-
- @pytest.mark.parametrize('angle_unit,expected_mask', [('radians', [1, 0, 0, 1]), ('degrees', [1, 0, 0, 0])])
- def test_apply_roi_fullsphere(self, angle_unit, expected_mask):
- self.viewer.add_data(self.data_fullsphere)
- viewer_state = self.viewer.state
- roi = RectangularROI(0.5, 1, 0, 0.5)
-
- viewer_state.angle_unit = angle_unit
- for proj in fullsphere_projections:
- viewer_state.plot_mode = proj
- assert len(self.viewer.layers) == 1
-
- self.viewer.apply_roi(roi)
-
- assert len(self.viewer.layers) == 2
- assert len(self.data_fullsphere.subsets) == 1
-
- subset = self.data_fullsphere.subsets[0]
- state = subset.subset_state
- assert isinstance(state, RoiSubsetState)
-
- assert state.pretransform
- pretrans = state.pretransform
- if angle_unit == 'degrees':
- assert isinstance(pretrans, RadianTransform)
- pretrans = pretrans._next_transform
- assert isinstance(pretrans, FullSphereLongitudeTransform)
- projtrans = pretrans._next_transform
- assert isinstance(projtrans, ProjectionMplTransform)
-
- assert_allclose(subset.to_mask(), expected_mask)
-
- assert projtrans._state['projection'] == proj
- assert_allclose(projtrans._state['x_lim'], [viewer_state.x_min, viewer_state.x_max])
- assert_allclose(projtrans._state['y_lim'], [viewer_state.y_min, viewer_state.y_max])
- assert projtrans._state['x_scale'] == 'linear'
- assert projtrans._state['y_scale'] == 'linear'
- subset.delete()
diff --git a/glue/viewers/scatter/qt/tests/test_python_export.py b/glue/viewers/scatter/qt/tests/test_python_export.py
deleted file mode 100644
index ab89994a3..000000000
--- a/glue/viewers/scatter/qt/tests/test_python_export.py
+++ /dev/null
@@ -1,301 +0,0 @@
-from itertools import product
-
-import numpy as np
-import matplotlib.pyplot as plt
-from astropy.utils import NumpyRNGContext
-
-from glue.core import Data, DataCollection
-from glue.app.qt.application import GlueApplication
-from glue.viewers.matplotlib.qt.tests.test_python_export import BaseTestExportPython, random_with_nan
-from glue.viewers.scatter.qt import ScatterViewer
-
-
-class TestExportPython(BaseTestExportPython):
-
- def setup_method(self, method):
-
- with NumpyRNGContext(12345):
- self.data = Data(**dict((name, random_with_nan(100, nan_index=idx + 1)) for idx, name in enumerate('abcdefgh')))
- self.data['angle'] = np.random.uniform(0, 360, 100)
- self.data_collection = DataCollection([self.data])
- self.app = GlueApplication(self.data_collection)
- self.viewer = self.app.new_data_viewer(ScatterViewer)
- self.viewer.add_data(self.data)
- self.viewer.state.x_att = self.data.id['a']
- self.viewer.state.y_att = self.data.id['b']
-
- def teardown_method(self, method):
- self.viewer.close()
- self.viewer = None
- self.app.close()
- self.app = None
-
- def test_simple(self, tmpdir):
- self.assert_same(tmpdir)
-
- def test_simple_legend(self, tmpdir):
- self.viewer.state.legend.visible = True
- self.assert_same(tmpdir)
-
- def test_simple_nofill(self, tmpdir):
- self.viewer.state.layers[0].fill = False
- self.viewer.state.layers[0].size_scaling = 10
- self.assert_same(tmpdir)
-
- def test_simple_visual(self, tmpdir):
- self.viewer.state.layers[0].color = 'blue'
- self.viewer.state.layers[0].markersize = 30
- self.viewer.state.layers[0].alpha = 0.5
- self.assert_same(tmpdir)
-
- def test_simple_visual_legend(self, tmpdir):
- self.viewer.state.legend.visible = True
- self.viewer.state.layers[0].color = 'blue'
- self.viewer.state.layers[0].markersize = 30
- self.viewer.state.layers[0].alpha = 0.5
- self.assert_same(tmpdir)
-
- def test_cmap_mode(self, tmpdir):
- self.viewer.state.layers[0].cmap_mode = 'Linear'
- self.viewer.state.layers[0].cmap_att = self.data.id['c']
- self.viewer.state.layers[0].cmap = plt.cm.BuGn
- self.viewer.state.layers[0].cmap_vmin = 0.2
- self.viewer.state.layers[0].cmap_vmax = 0.7
- self.viewer.state.layers[0].alpha = 0.8
- self.assert_same(tmpdir)
-
- def test_cmap_mode_nofill(self, tmpdir):
- self.viewer.state.layers[0].fill = False
- self.test_cmap_mode(tmpdir)
-
- def test_size_mode(self, tmpdir):
- self.viewer.state.layers[0].size_mode = 'Linear'
- self.viewer.state.layers[0].size_att = self.data.id['d']
- self.viewer.state.layers[0].size_vmin = 0.1
- self.viewer.state.layers[0].size_vmax = 0.8
- self.viewer.state.layers[0].size_scaling = 0.4
- self.viewer.state.layers[0].alpha = 0.7
- self.assert_same(tmpdir)
-
- def test_size_mode_legend(self, tmpdir):
- self.viewer.state.legend.visible = True
- self.viewer.state.layers[0].size_mode = 'Linear'
- self.viewer.state.layers[0].size_att = self.data.id['d']
- self.viewer.state.layers[0].size_vmin = 0.1
- self.viewer.state.layers[0].size_vmax = 0.8
- self.viewer.state.layers[0].size_scaling = 0.4
- self.viewer.state.layers[0].alpha = 0.7
- self.assert_same(tmpdir)
-
- def test_size_mode_nofill(self, tmpdir):
- self.viewer.state.layers[0].fill = False
- self.test_size_mode(tmpdir)
-
- def test_line(self, tmpdir):
- self.viewer.state.layers[0].line_visible = True
- self.viewer.state.layers[0].linewidth = 10
- self.viewer.state.layers[0].linestype = 'dashed'
- self.viewer.state.layers[0].color = 'orange'
- self.viewer.state.layers[0].alpha = 0.7
- self.viewer.state.layers[0].markersize = 100
- self.assert_same(tmpdir, tol=5)
-
- def test_line_cmap(self, tmpdir):
- self.viewer.state.layers[0].cmap_mode = 'Linear'
- self.viewer.state.layers[0].cmap_vmin = 0.2
- self.viewer.state.layers[0].cmap_vmax = 0.7
- self.viewer.state.layers[0].cmap = plt.cm.BuGn
- self.test_line(tmpdir)
-
- def test_errorbarx(self, tmpdir):
- self.viewer.state.layers[0].xerr_visible = True
- self.viewer.state.layers[0].xerr_att = self.data.id['e']
- self.viewer.state.layers[0].color = 'purple'
- self.viewer.state.layers[0].alpha = 0.5
- self.assert_same(tmpdir)
-
- def test_errorbary(self, tmpdir):
- self.viewer.state.layers[0].yerr_visible = True
- self.viewer.state.layers[0].yerr_att = self.data.id['f']
- self.viewer.state.layers[0].color = 'purple'
- self.viewer.state.layers[0].alpha = 0.5
- self.assert_same(tmpdir)
-
- def test_errorbarxy(self, tmpdir):
- self.viewer.state.layers[0].xerr_visible = True
- self.viewer.state.layers[0].xerr_att = self.data.id['e']
- self.viewer.state.layers[0].yerr_visible = True
- self.viewer.state.layers[0].yerr_att = self.data.id['f']
- self.viewer.state.layers[0].color = 'purple'
- self.viewer.state.layers[0].alpha = 0.5
- self.assert_same(tmpdir)
-
- def test_errorbarxy_legend(self, tmpdir):
- self.viewer.state.legend.visible = True
- self.viewer.state.layers[0].xerr_visible = True
- self.viewer.state.layers[0].xerr_att = self.data.id['e']
- self.viewer.state.layers[0].yerr_visible = True
- self.viewer.state.layers[0].yerr_att = self.data.id['f']
- self.viewer.state.layers[0].color = 'purple'
- self.viewer.state.layers[0].alpha = 0.5
- self.assert_same(tmpdir)
-
- def test_errorbarxy_cmap(self, tmpdir):
- self.viewer.state.layers[0].cmap_mode = 'Linear'
- self.viewer.state.layers[0].cmap_vmin = 0.2
- self.viewer.state.layers[0].cmap_vmax = 0.7
- self.viewer.state.layers[0].cmap = plt.cm.BuGn
- self.test_errorbarxy(tmpdir)
-
- def _vector_common(self, tmpdir):
- self.viewer.state.layers[0].vector_visible = True
- self.viewer.state.layers[0].vy_att = self.data.id['g']
- self.viewer.state.layers[0].vector_arrowhead = True
- self.viewer.state.layers[0].vector_origin = 'tail'
- self.viewer.state.layers[0].vector_scaling = 1.5
- self.viewer.state.layers[0].color = 'teal'
- self.viewer.state.layers[0].alpha = 0.9
- self.assert_same(tmpdir, tol=1)
-
- def test_vector_cartesian(self, tmpdir):
- self.viewer.state.layers[0].vector_mode = 'Cartesian'
- self.viewer.state.layers[0].vx_att = self.data.id['h']
- self._vector_common(tmpdir)
-
- def test_vector_polar(self, tmpdir):
- self.viewer.state.layers[0].vector_mode = 'Polar'
- self.viewer.state.layers[0].vx_att = self.data.id['angle']
- self._vector_common(tmpdir)
-
- def test_vector_cartesian_cmap(self, tmpdir):
- self.viewer.state.layers[0].cmap_mode = 'Linear'
- self.viewer.state.layers[0].cmap_vmin = 0.2
- self.viewer.state.layers[0].cmap_vmax = 0.7
- self.viewer.state.layers[0].cmap = plt.cm.BuGn
- self.test_vector_cartesian(tmpdir)
-
- def test_vector_cartesian_xflip(self, tmpdir):
- # Regression test for a bug that caused vectors to not be flipped
- self.viewer.state.layers[0].vector_mode = 'Cartesian'
- self.viewer.state.layers[0].vx_att = self.data.id['h']
- self.viewer.state.flip_x()
- self._vector_common(tmpdir)
-
- def test_subset(self, tmpdir):
- self.data_collection.new_subset_group('mysubset', self.data.id['a'] > 0.5)
- self.assert_same(tmpdir)
-
- def test_density_map_with_subset(self, tmpdir):
- self.viewer.state.dpi = 2
- self.viewer.state.layers[0].density_map = True
- self.data_collection.new_subset_group('mysubset', self.data.id['a'] > 0.5)
- self.assert_same(tmpdir)
-
- def test_density_map_cmap_with_subset(self, tmpdir):
- self.viewer.state.dpi = 2
- self.viewer.state.layers[0].density_map = True
- self.viewer.state.layers[0].cmap_mode = 'Linear'
- self.viewer.state.layers[0].cmap_vmin = 0.2
- self.viewer.state.layers[0].cmap_vmax = 0.7
- self.viewer.state.layers[0].cmap = plt.cm.BuGn
- self.data_collection.new_subset_group('mysubset', self.data.id['a'] > 0.5)
- self.assert_same(tmpdir)
-
- def test_density_map_cmap_with_subset_legend(self, tmpdir):
- self.viewer.state.legend.visible = True
- self.viewer.state.dpi = 2
- self.viewer.state.layers[0].density_map = True
- self.viewer.state.layers[0].cmap_mode = 'Linear'
- self.viewer.state.layers[0].cmap_vmin = 0.2
- self.viewer.state.layers[0].cmap_vmax = 0.7
- self.viewer.state.layers[0].cmap = plt.cm.BuGn
- self.data_collection.new_subset_group('mysubset', self.data.id['a'] > 0.5)
- self.assert_same(tmpdir)
-
- def test_cmap_mode_change(self, tmpdir):
- # Regression test for a bug that caused scatter markers to not change
- # color when going from Linear to Fixed mode
- self.viewer.state.layers[0].size_mode = 'Linear'
- self.viewer.state.layers[0].cmap_mode = 'Linear'
- self.viewer.state.layers[0].cmap_mode = 'Fixed'
- self.assert_same(tmpdir)
-
- def test_density_map_change(self, tmpdir):
- # Regression test for a bug that caused the density map to still
- # be visible if using color-coding with the density map then
- # switching to markers.
- self.viewer.state.layers[0].density_map = True
- self.viewer.state.layers[0].cmap_mode = 'Linear'
- self.viewer.state.layers[0].cmap = plt.cm.BuGn
- self.viewer.state.layers[0].density_map = False
- self.assert_same(tmpdir)
-
- def test_simple_polar_plot_degrees(self, tmpdir):
- self.viewer.state.plot_mode = 'polar'
- self.viewer.state.angle_unit = 'degrees'
- self.viewer.state.x_att = self.data.id['c']
- self.viewer.state.y_att = self.data.id['d']
- self.assert_same(tmpdir)
-
- def test_simple_polar_plot_radians(self, tmpdir):
- self.viewer.state.plot_mode = 'polar'
- self.viewer.state.angle_unit = 'radians'
- self.viewer.state.x_att = self.data.id['c']
- self.viewer.state.y_att = self.data.id['d']
- self.assert_same(tmpdir)
-
- def _fullsphere_common_test(self, tmpdir):
- # Note that all the full-sphere projections have the same bounds,
- # so we can use the same sets of min/max values
- x_bounds = self.viewer.state.x_min, self.viewer.state.x_max
- y_bounds = self.viewer.state.y_min, self.viewer.state.y_max
- for order in product([True, False], repeat=2):
- self.viewer.state.x_min, self.viewer.state.x_max = sorted(x_bounds, reverse=order[0])
- self.viewer.state.y_min, self.viewer.state.y_max = sorted(y_bounds, reverse=order[1])
- self.viewer.state.plot_mode = 'aitoff'
- self.viewer.state.x_att = self.data.id['c']
- self.viewer.state.y_att = self.data.id['d']
- self.assert_same(tmpdir)
- self.viewer.state.plot_mode = 'hammer'
- self.viewer.state.x_att = self.data.id['e']
- self.viewer.state.y_att = self.data.id['f']
- self.assert_same(tmpdir)
- self.viewer.state.plot_mode = 'lambert'
- self.viewer.state.x_att = self.data.id['g']
- self.viewer.state.y_att = self.data.id['h']
- self.assert_same(tmpdir)
- self.viewer.state.plot_mode = 'mollweide'
- self.viewer.state.x_att = self.data.id['a']
- self.viewer.state.y_att = self.data.id['b']
- self.assert_same(tmpdir)
-
- def test_full_sphere_degrees(self, tmpdir):
- self.viewer.state.angle_unit = 'degrees'
- self._fullsphere_common_test(tmpdir)
-
- def test_full_sphere_radians(self, tmpdir):
- self.viewer.state.angle_unit = 'radians'
- self._fullsphere_common_test(tmpdir)
-
- def test_cmap_size_noncartesian(self, tmpdir):
- self.viewer.state.layers[0].size_mode = 'Linear'
- self.viewer.state.layers[0].cmap_mode = 'Linear'
- for proj in ['polar', 'aitoff', 'hammer', 'lambert', 'mollweide']:
- self.viewer.state.plot_mode = proj
- self.assert_same(tmpdir)
-
- def test_vectors_noncartesian(self, tmpdir):
- for proj in ['polar', 'aitoff', 'hammer', 'lambert', 'mollweide']:
- self.viewer.state.plot_mode = proj
- self._vector_common(tmpdir)
-
- def test_errorbarxy_noncartesian(self, tmpdir):
- self.viewer.state.layers[0].xerr_visible = True
- self.viewer.state.layers[0].xerr_att = self.data.id['e']
- self.viewer.state.layers[0].yerr_visible = True
- self.viewer.state.layers[0].yerr_att = self.data.id['f']
- self.viewer.state.layers[0].color = 'purple'
- self.viewer.state.layers[0].alpha = 0.5
- for proj in ['polar', 'aitoff', 'hammer', 'lambert', 'mollweide']:
- self.viewer.state.plot_mode = proj
- self.assert_same(tmpdir)
diff --git a/glue/viewers/scatter/state.py b/glue/viewers/scatter/state.py
index 7c20aa83a..0ad007bb9 100644
--- a/glue/viewers/scatter/state.py
+++ b/glue/viewers/scatter/state.py
@@ -4,7 +4,7 @@
from glue.core import BaseData, Subset
-from glue.config import colormaps
+from glue.config import colormaps, stretches
from glue.viewers.matplotlib.state import (MatplotlibDataViewerState,
MatplotlibLayerState,
DeferredDrawCallbackProperty as DDCProperty,
@@ -327,13 +327,8 @@ def __init__(self, viewer_state=None, layer=None, **kwargs):
ScatterLayerState.vector_origin.set_choices(self, ['tail', 'middle', 'tip'])
ScatterLayerState.vector_origin.set_display_func(self, vector_origin_display.get)
- stretch_display = {'linear': 'Linear',
- 'sqrt': 'Square Root',
- 'arcsinh': 'Arcsinh',
- 'log': 'Logarithmic'}
-
ScatterLayerState.stretch.set_choices(self, ['linear', 'sqrt', 'arcsinh', 'log'])
- ScatterLayerState.stretch.set_display_func(self, stretch_display.get)
+ ScatterLayerState.stretch.set_display_func(self, stretches.display_func)
if self.viewer_state is not None:
self.viewer_state.add_callback('x_att', self._on_xy_change, priority=10000)
diff --git a/glue/viewers/table/qt/__init__.py b/glue/viewers/table/qt/__init__.py
index 314de07c9..6220498c9 100644
--- a/glue/viewers/table/qt/__init__.py
+++ b/glue/viewers/table/qt/__init__.py
@@ -1,6 +1,4 @@
-from .data_viewer import TableViewer, TableLayerArtist # noqa
-
-
-def setup():
- from glue.config import qt_client
- qt_client.add(TableViewer)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.table.qt is deprecated, use glue_qt.viewers.table instead', GlueDeprecationWarning)
+from glue_qt.viewers.table import * # noqa
diff --git a/glue/viewers/table/qt/data_viewer.py b/glue/viewers/table/qt/data_viewer.py
index b347632d1..e54734d0b 100644
--- a/glue/viewers/table/qt/data_viewer.py
+++ b/glue/viewers/table/qt/data_viewer.py
@@ -1,405 +1,4 @@
-import os
-from functools import lru_cache
-import re
-
-import numpy as np
-
-from qtpy.QtCore import Qt
-from qtpy import QtCore, QtGui, QtWidgets
-from matplotlib.colors import ColorConverter
-
-from echo.qt import autoconnect_callbacks_to_qt
-from glue.utils.qt import get_qapp
-from glue.config import viewer_tool
-from glue.core import BaseData, Data
-from glue.utils.qt import load_ui
-from glue.viewers.common.qt.data_viewer import DataViewer
-from glue.viewers.common.qt.toolbar import BasicToolbar
-from glue.viewers.common.tool import CheckableTool
-from glue.viewers.common.layer_artist import LayerArtist
-from glue.core.subset import ElementSubsetState
-from glue.utils.colors import alpha_blend_colors
-from glue.utils.qt import mpl_to_qt_color, messagebox_on_error
-from glue.core.exceptions import IncompatibleAttribute
-from glue.viewers.table.compat import update_table_viewer_state
-from glue.viewers.table.state import TableViewerState
-
-try:
- import dask.array as da
- DASK_INSTALLED = True
-except ImportError:
- DASK_INSTALLED = False
-
-__all__ = ['TableViewer', 'TableLayerArtist']
-
-COLOR_CONVERTER = ColorConverter()
-
-
-class DataTableModel(QtCore.QAbstractTableModel):
-
- def __init__(self, table_viewer):
- super(DataTableModel, self).__init__()
- if table_viewer.data.ndim != 1:
- raise ValueError("Can only use Table widget for 1D data")
- self._table_viewer = table_viewer
- self._data = table_viewer.data
- self._state = table_viewer.state
- self.filter_mask = None
- self.show_coords = False
- self.order = np.arange(self._data.shape[0])
- self._update_visible()
-
- def data_changed(self):
- top_left = self.index(0, 0)
- bottom_right = self.index(self.columnCount(), self.rowCount())
- self._update_visible()
- self.data_by_row_and_column.cache_clear()
- self.dataChanged.emit(top_left, bottom_right)
- self.layoutChanged.emit()
-
- @property
- def columns(self):
- if self.show_coords:
- return self._data.components
- else:
- return self._data.main_components + self._data.derived_components
-
- def columnCount(self, index=None):
- return len(self.columns)
-
- def rowCount(self, index=None):
- # Qt bug: Crashes on tables bigger than this
- return min(self.order_visible.size, 71582788)
-
- def headerData(self, section, orientation, role):
- if role != Qt.DisplayRole:
- return None
-
- if orientation == Qt.Horizontal:
- column_name = self.columns[section].label
- units = self._data.get_component(self.columns[section]).units
- if units is not None and units != '':
- column_name += "\n{0}".format(units)
- return column_name
- elif orientation == Qt.Vertical:
- return str(self.order_visible[section])
-
- def data(self, index, role):
-
- if not index.isValid():
- return None
-
- return self.data_by_row_and_column(index.row(), index.column(), role)
-
- # The data() method gets called many times, often with the same parameters,
- # for example if bringing the window to the foreground/background, shifting
- # up/down/left/right by one cell, etc. This can be very slow when e.g. dask
- # columns are present so we cache the most recent 65536 calls which should
- # have a reasonably sensible memory footprint.
- @lru_cache(maxsize=65536)
- def data_by_row_and_column(self, row, column, role):
-
- if role == Qt.DisplayRole:
-
- c = self.columns[column]
- idx = self.order_visible[row]
- comp = self._data[c]
- value = comp[idx]
- if isinstance(value, bytes):
- return value.decode('ascii')
- else:
- if DASK_INSTALLED and isinstance(value, da.Array):
- return str(value.compute())
- else:
- return str(comp[idx])
-
- elif role == Qt.BackgroundRole:
-
- idx = self.order_visible[row]
-
- # Find all subsets that this index is part of
- colors = []
- for layer_artist in self._table_viewer.layers[::-1]:
- if isinstance(layer_artist.layer, BaseData):
- continue
- if layer_artist.visible:
- subset = layer_artist.layer
- try:
- if subset.to_mask(view=slice(idx, idx + 1))[0]:
- colors.append(subset.style.color)
- except IncompatibleAttribute as exc:
- # Only disable the layer if enabled, as otherwise we
- # will recursively call clear and _refresh, causing
- # an infinite loop and performance issues.
- # Also make sure that a disabled layer is not visible
- if layer_artist.enabled:
- layer_artist.disable_invalid_attributes(*exc.args)
- layer_artist.visible = False
- else:
- layer_artist.enabled = True
-
- # Blend the colors using alpha blending
- if len(colors) > 0:
- color = alpha_blend_colors(colors, additional_alpha=0.5)
- color = mpl_to_qt_color(color)
- return QtGui.QBrush(color)
-
- def sort(self, column, ascending):
- c = self.columns[column]
- comp = self._data.get_component(c)
- self.order = np.argsort(comp.data)
- if ascending == Qt.DescendingOrder:
- self.order = self.order[::-1]
- self._update_visible()
- self.data_by_row_and_column.cache_clear()
- self.layoutChanged.emit()
-
- def get_filter_mask(self):
- if (self._state.filter is None) or (self._state.filter_att is None):
- self.filter_mask = np.ones(self.order.shape, dtype=bool)
- return
- comp = self._data.get_component(self._state.filter_att)
-
- if self._state.regex:
- p = re.compile(self._state.filter)
- self.filter_mask = np.array([bool(p.search(x)) for x in comp.data])
- else:
- self.filter_mask = np.array([self._state.filter in x for x in comp.data])
- self.data_changed() # This might be overkill
-
- def _update_visible(self):
- """
- Given which layers are visible or not, convert order to order_visible
- after applying the current filter_mask
- """
-
- self.data_by_row_and_column.cache_clear()
-
- # First, if the data layer is visible, show all rows
- for layer_artist in self._table_viewer.layers:
- if layer_artist.visible and isinstance(layer_artist.layer, BaseData):
- if self.filter_mask is None:
- self.order_visible = self.order
- return
- else:
- mask = self.filter_mask[self.order]
- self.order_visible = self.order[mask]
- return
-
- # If not then we need to show only the rows with visible subsets
- visible = np.zeros(self.order.shape, dtype=bool)
- for layer_artist in self._table_viewer.layers:
- if layer_artist.visible:
- mask = layer_artist.layer.to_mask()[self.order]
- if DASK_INSTALLED and isinstance(mask, da.Array):
- mask = mask.compute()
- visible |= mask
- if self.filter_mask is not None:
- visible &= self.filter_mask[self.order]
-
- self.order_visible = self.order[visible]
-
-
-class TableLayerArtist(LayerArtist):
-
- def __init__(self, table_viewer, viewer_state, layer_state=None, layer=None):
- self._table_viewer = table_viewer
- super(TableLayerArtist, self).__init__(viewer_state,
- layer_state=layer_state,
- layer=layer)
- self.redraw()
-
- def _refresh(self):
- self._table_viewer.model.data_changed()
-
- def redraw(self):
- self._refresh()
-
- def update(self):
- self._refresh()
-
- def clear(self):
- self._refresh()
-
-
-@viewer_tool
-class RowSelectTool(CheckableTool):
-
- tool_id = 'table:rowselect'
- icon = 'glue_row_select'
- action_text = 'Select row(s)'
- tool_tip = ('Select rows by clicking on rows and pressing enter '
- 'once the selection is ready to be applied')
- status_tip = ('CLICK to select, press ENTER to finalize selection, '
- 'ALT+CLICK or ALT+UP/DOWN to apply selection immediately')
-
- def __init__(self, viewer):
- super(RowSelectTool, self).__init__(viewer)
- self.deactivate()
-
- def activate(self):
- self.viewer.ui.table.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
-
- def deactivate(self, block=False):
- # Don't do anything if the viewer has already been closed
- if self.viewer is None:
- return
- self.viewer.ui.table.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
- self.viewer.ui.table.clearSelection()
-
-
-class TableViewWithSelectionSignal(QtWidgets.QTableView):
- """
- This is the TableViewer.ui.table object
- """
- selection_changed = QtCore.Signal()
-
- def selectionChanged(self, *args, **kwargs):
- self.selection_changed.emit()
- super(TableViewWithSelectionSignal, self).selectionChanged(*args, **kwargs)
-
-
-class TableViewer(DataViewer):
-
- LABEL = "Table Viewer"
-
- _toolbar_cls = BasicToolbar
- _data_artist_cls = TableLayerArtist
- _subset_artist_cls = TableLayerArtist
- _state_cls = TableViewerState
-
- inherit_tools = False
- tools = ['table:rowselect', 'window']
- subtools = {
- 'window': ['window:movetab', 'window:title']
- }
-
- def __init__(self, session, state=None, parent=None, widget=None):
-
- super(TableViewer, self).__init__(session, state=state, parent=parent)
-
- self.ui = load_ui('data_viewer.ui',
- directory=os.path.dirname(__file__))
- self.setCentralWidget(self.ui)
-
- hdr = self.ui.table.horizontalHeader()
- hdr.setStretchLastSection(True)
- hdr.setSectionResizeMode(hdr.Interactive)
-
- hdr = self.ui.table.verticalHeader()
- hdr.setSectionResizeMode(hdr.Interactive)
-
- self.data = None
- self.model = None
-
- self._connections = autoconnect_callbacks_to_qt(self.state, self.ui)
-
- self.state.add_callback('regex', self._on_filter_changed)
- self.state.add_callback('filter', self._on_filter_changed)
- self.state.add_callback('filter_att', self._on_filter_changed)
-
- self.ui.table.selection_changed.connect(self.selection_changed)
- self.state.add_callback('layers', self._on_layers_changed)
- self._on_layers_changed()
-
- def selection_changed(self):
- app = get_qapp()
- if app.queryKeyboardModifiers() == Qt.AltModifier:
- self.finalize_selection(clear=False)
-
- def keyPressEvent(self, event):
- if self.toolbar.active_tool is self.toolbar.tools['table:rowselect']:
- if event.key() in [Qt.Key_Enter, Qt.Key_Return]:
- self.finalize_selection()
- super(TableViewer, self).keyPressEvent(event)
-
- def finalize_selection(self, clear=True):
- model = self.ui.table.selectionModel()
- selected_rows = [self.model.order_visible[x.row()] for x in model.selectedRows()]
- subset_state = ElementSubsetState(indices=selected_rows, data=self.data)
- mode = self.session.edit_subset_mode
- mode.update(self._data, subset_state, focus_data=self.data)
- if clear:
- # We block the signals here to make sure that we don't update
- # the subset again once the selection is cleared.
- self.ui.table.blockSignals(True)
- self.ui.table.clearSelection()
- self.ui.table.blockSignals(False)
-
- def _on_filter_changed(self, *args):
- # If we change the filter we deactivate the toolbar to keep
- # any subset defined before we change what is displayed
- if self.toolbar.active_tool is self.toolbar.tools['table:rowselect']:
- old_tool = self.toolbar.active_tool
- old_tool.deactivate(block=True)
- button = self.toolbar.actions[old_tool.tool_id]
- if button.isChecked():
- button.setChecked(False)
- if self.model:
- self.model.get_filter_mask()
-
- def _on_layers_changed(self, *args):
- for layer_state in self.state.layers:
- if isinstance(layer_state.layer, BaseData):
- break
- else:
- return
-
- # If we aren't changing the data layer, we don't need to
- # reset the model, just update visible rows
- if layer_state.layer == self.data:
- self.model._update_visible()
- return
-
- self.data = layer_state.layer
-
- self.setUpdatesEnabled(False)
- self.model = DataTableModel(self)
- self.model.get_filter_mask()
-
- self.ui.table.setModel(self.model)
- self.setUpdatesEnabled(True)
-
- @messagebox_on_error("Failed to add data")
- def add_data(self, data):
- with self._layer_artist_container.ignore_empty():
- self.state.layers[:] = []
- return super(TableViewer, self).add_data(data)
-
- @messagebox_on_error("Failed to add subset")
- def add_subset(self, subset):
-
- if self.data is None:
- self.add_data(subset.data)
- self.state.layers[0].visible = False
- elif subset.data != self.data:
- raise ValueError("subset parent data does not match existing table data")
-
- return super(TableViewer, self).add_subset(subset)
-
- @property
- def window_title(self):
- if self.state.title:
- return self.state.title
- elif len(self.state.layers) > 0:
- return 'Table: ' + self.state.layers[0].layer.label
- else:
- return 'Table'
-
- def closeEvent(self, event):
- """
- On close, Qt seems to scan through the entire model
- if the data set is big. To sidestep that,
- we swap out with a tiny data set before closing
- """
- super(TableViewer, self).closeEvent(event)
- if self.model is not None:
- self.model._data = Data(x=[0])
- event.accept()
-
- def get_layer_artist(self, cls, layer=None, layer_state=None):
- return cls(self, self.state, layer=layer, layer_state=layer_state)
-
- @staticmethod
- def update_viewer_state(rec, context):
- return update_table_viewer_state(rec, context)
+import warnings
+from glue.utils.error import GlueDeprecationWarning
+warnings.warn('Importing from glue.viewers.table.qt.data_viewer is deprecated, use glue_qt.viewers.table.data_viewer instead', GlueDeprecationWarning)
+from glue_qt.viewers.table.data_viewer import * # noqa
diff --git a/glue/viewers/table/qt/data_viewer.ui b/glue/viewers/table/qt/data_viewer.ui
deleted file mode 100644
index 629809f2c..000000000
--- a/glue/viewers/table/qt/data_viewer.ui
+++ /dev/null
@@ -1,104 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 742
- 612
-
-
-
- Form
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 60
- 20
-
-
-
-
- -
-
-
- Search:
-
-
-
- -
-
-
- -
-
-
- in
-
-
-
- -
-
-
- -
-
-
- Use regex
-
-
-
-
-
- -
-
-
-
-
-
- QAbstractItemView::NoEditTriggers
-
-
- QAbstractItemView::ExtendedSelection
-
-
- QAbstractItemView::SelectRows
-
-
- true
-
-
- 107
-
-
- false
-
-
- true
-
-
- false
-
-
-
-
-
-
-
-
-
- TableViewWithSelectionSignal
- QTableView
- glue.viewers.table.qt.data_viewer
-
-
-
-
-
diff --git a/glue/viewers/table/qt/tests/__init__.py b/glue/viewers/table/qt/tests/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/glue/viewers/table/qt/tests/test_data_viewer.py b/glue/viewers/table/qt/tests/test_data_viewer.py
deleted file mode 100644
index 0c2a88a13..000000000
--- a/glue/viewers/table/qt/tests/test_data_viewer.py
+++ /dev/null
@@ -1,736 +0,0 @@
-import pytest
-import numpy as np
-from unittest.mock import MagicMock, patch
-
-from qtpy import QtCore, QtGui
-from qtpy.QtCore import Qt
-
-from glue.utils.qt import get_qapp, process_events
-from glue.core import Data, DataCollection, BaseData
-from glue.utils.qt import qt_to_mpl_color
-from glue.app.qt import GlueApplication
-
-from ..data_viewer import DataTableModel, TableViewer
-
-from glue.core.edit_subset_mode import AndNotMode, OrMode, ReplaceMode
-from glue.tests.helpers import requires_pyqt_gt_59_or_pyside2
-
-
-class TestDataTableModel():
-
- def setup_method(self, method):
- self.gapp = GlueApplication()
- self.viewer = self.gapp.new_data_viewer(TableViewer)
- self.data = Data(x=[1, 2, 3, 4], y=[2, 3, 4, 5])
- self.gapp.data_collection.append(self.data)
- self.viewer.add_data(self.data)
- self.model = DataTableModel(self.viewer)
-
- def teardown_method(self, method):
- self.gapp.close()
- self.gapp = None
-
- def test_column_count(self):
- assert self.model.columnCount() == 2
-
- def test_column_count_hidden(self):
- self.model.show_coords = True
- assert self.model.columnCount() == 3
-
- def test_header_data(self):
- for i, c in enumerate(self.data.main_components):
- result = self.model.headerData(i, Qt.Horizontal, Qt.DisplayRole)
- assert result == c.label
-
- for i in range(self.data.size):
- result = self.model.headerData(i, Qt.Vertical, Qt.DisplayRole)
- assert result == str(i)
-
- def test_row_count(self):
- assert self.model.rowCount() == 4
-
- def test_data(self):
- for i, c in enumerate(self.data.main_components):
- for j in range(self.data.size):
- idx = self.model.index(j, i)
- result = self.model.data(idx, Qt.DisplayRole)
- assert float(result) == self.data[c, j]
-
- @pytest.mark.xfail
- def test_data_2d(self):
- self.data = Data(x=[[1, 2], [3, 4]], y=[[2, 3], [4, 5]])
- self.model = DataTableModel(self.data)
- for i, c in enumerate(self.data.main_components):
- for j in range(self.data.size):
- idx = self.model.index(j, i)
- result = self.model.data(idx, Qt.DisplayRole)
- assert float(result) == self.data[c].ravel()[j]
-
-
-def check_values_and_color(model, data, colors):
-
- for i in range(len(colors)):
-
- for j, colname in enumerate(sorted(data)):
-
- # Get index of cell
- idx = model.index(i, j)
-
- # Check values
- value = model.data(idx, Qt.DisplayRole)
- assert value == str(data[colname][i])
-
- # Check colors
- brush = model.data(idx, Qt.BackgroundRole)
- if colors[i] is None:
- assert brush is None
- else:
- assert qt_to_mpl_color(brush.color()) == colors[i]
-
-
-def test_table_widget(tmpdir):
-
- # Start off by creating a glue application instance with a table viewer and
- # some data pre-loaded.
-
- app = get_qapp()
-
- d = Data(a=[1, 2, 3, 4, 5],
- b=[3.2, 1.2, 4.5, 3.3, 2.2],
- c=['e', 'b', 'c', 'a', 'f'])
-
- dc = DataCollection([d])
-
- gapp = GlueApplication(dc)
-
- widget = gapp.new_data_viewer(TableViewer)
- widget.add_data(d)
-
- subset_mode = gapp._session.edit_subset_mode
-
- # Create two subsets
-
- sg1 = dc.new_subset_group('D <= 3', d.id['a'] <= 3)
- sg1.style.color = '#aa0000'
- sg2 = dc.new_subset_group('1 < D < 4', (d.id['a'] > 1) & (d.id['a'] < 4))
- sg2.style.color = '#0000cc'
-
- model = widget.ui.table.model()
-
- # We now check what the data and colors of the table are, and try various
- # sorting methods to make sure that things are still correct.
-
- data = {'a': [1, 2, 3, 4, 5],
- 'b': [3.2, 1.2, 4.5, 3.3, 2.2],
- 'c': ['e', 'b', 'c', 'a', 'f']}
-
- colors = ['#aa0000', '#380088', '#380088', None, None]
-
- check_values_and_color(model, data, colors)
-
- model.sort(1, Qt.AscendingOrder)
-
- data = {'a': [2, 5, 1, 4, 3],
- 'b': [1.2, 2.2, 3.2, 3.3, 4.5],
- 'c': ['b', 'f', 'e', 'a', 'c']}
-
- colors = ['#380088', None, '#aa0000', None, '#380088']
-
- check_values_and_color(model, data, colors)
-
- model.sort(2, Qt.AscendingOrder)
-
- data = {'a': [4, 2, 3, 1, 5],
- 'b': [3.3, 1.2, 4.5, 3.2, 2.2],
- 'c': ['a', 'b', 'c', 'e', 'f']}
-
- colors = [None, '#380088', '#380088', '#aa0000', None]
-
- check_values_and_color(model, data, colors)
-
- model.sort(0, Qt.DescendingOrder)
-
- data = {'a': [5, 4, 3, 2, 1],
- 'b': [2.2, 3.3, 4.5, 1.2, 3.2],
- 'c': ['f', 'a', 'c', 'b', 'e']}
-
- colors = [None, None, '#380088', '#380088', '#aa0000']
-
- check_values_and_color(model, data, colors)
-
- model.sort(0, Qt.AscendingOrder)
-
- # We now modify the subsets using the table.
-
- selection = widget.ui.table.selectionModel()
-
- widget.toolbar.actions['table:rowselect'].toggle()
-
- def press_key(key):
- event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, key, Qt.NoModifier)
- app.postEvent(widget.ui.table, event)
- app.processEvents()
-
- process_events()
-
- # We now use key presses to navigate down to the third row
-
- press_key(Qt.Key_Tab)
- press_key(Qt.Key_Down)
- press_key(Qt.Key_Down)
-
- process_events()
-
- indices = selection.selectedRows()
-
- # We make sure that the third row is selected
-
- assert len(indices) == 1
- assert indices[0].row() == 2
-
- # At this point, the subsets haven't changed yet
-
- np.testing.assert_equal(d.subsets[0].to_mask(), [1, 1, 1, 0, 0])
- np.testing.assert_equal(d.subsets[1].to_mask(), [0, 1, 1, 0, 0])
-
- # We specify that we are editing the second subset, and use a 'not' logical
- # operation to remove the currently selected line from the second subset.
-
- subset_mode.edit_subset = [d.subsets[1]]
- subset_mode.mode = AndNotMode
-
- press_key(Qt.Key_Enter)
-
- np.testing.assert_equal(d.subsets[0].to_mask(), [1, 1, 1, 0, 0])
- np.testing.assert_equal(d.subsets[1].to_mask(), [0, 1, 0, 0, 0])
-
- # At this point, the selection should be cleared
-
- indices = selection.selectedRows()
- assert len(indices) == 0
-
- # We move to the fourth row and now do an 'or' selection with the first
- # subset.
-
- press_key(Qt.Key_Down)
-
- subset_mode.mode = OrMode
-
- subset_mode.edit_subset = [d.subsets[0]]
-
- press_key(Qt.Key_Enter)
-
- np.testing.assert_equal(d.subsets[0].to_mask(), [1, 1, 1, 1, 0])
- np.testing.assert_equal(d.subsets[1].to_mask(), [0, 1, 0, 0, 0])
-
- # Finally we move to the fifth row and deselect all subsets so that
- # pressing enter now creates a new subset.
-
- press_key(Qt.Key_Down)
-
- subset_mode.mode = ReplaceMode
-
- subset_mode.edit_subset = None
-
- press_key(Qt.Key_Enter)
-
- np.testing.assert_equal(d.subsets[0].to_mask(), [1, 1, 1, 1, 0])
- np.testing.assert_equal(d.subsets[1].to_mask(), [0, 1, 0, 0, 0])
- np.testing.assert_equal(d.subsets[2].to_mask(), [0, 0, 0, 0, 1])
-
- # Make the color for the new subset deterministic
- dc.subset_groups[2].style.color = '#bababa'
-
- # Now finally check saving and restoring session
-
- session_file = tmpdir.join('table.glu').strpath
-
- gapp.save_session(session_file)
-
- gapp2 = GlueApplication.restore_session(session_file)
- gapp2.show()
-
- d = gapp2.data_collection[0]
-
- widget2 = gapp2.viewers[0][0]
-
- model2 = widget2.ui.table.model()
-
- data = {'a': [1, 2, 3, 4, 5],
- 'b': [3.2, 1.2, 4.5, 3.3, 2.2],
- 'c': ['e', 'b', 'c', 'a', 'f']}
-
- # Need to take into account new selections above
- colors = ['#aa0000', '#380088', '#aa0000', "#aa0000", "#bababa"]
-
- check_values_and_color(model2, data, colors)
-
-
-def test_table_widget_session_no_subset(tmpdir):
-
- # Regression test for a bug that caused table viewers with no subsets to
- # not be restored correctly and instead raise an exception.
-
- app = get_qapp() # noqa
-
- d = Data(a=[1, 2, 3, 4, 5],
- b=[3.2, 1.2, 4.5, 3.3, 2.2],
- c=['e', 'b', 'c', 'a', 'f'], label='test')
-
- dc = DataCollection([d])
-
- gapp = GlueApplication(dc)
-
- widget = gapp.new_data_viewer(TableViewer)
- widget.add_data(d)
-
- session_file = tmpdir.join('table.glu').strpath
-
- gapp.save_session(session_file)
-
- gapp2 = GlueApplication.restore_session(session_file)
- gapp2.show()
-
- gapp2.data_collection[0]
- gapp2.viewers[0][0]
-
-
-def test_change_components():
-
- # Regression test for a bug that caused table viewers to not update when
- # adding/removing components.
-
- app = get_qapp() # noqa
-
- d = Data(a=[1, 2, 3, 4, 5],
- b=[3.2, 1.2, 4.5, 3.3, 2.2],
- c=['e', 'b', 'c', 'a', 'f'], label='test')
-
- dc = DataCollection([d])
-
- gapp = GlueApplication(dc)
-
- viewer = gapp.new_data_viewer(TableViewer)
- viewer.add_data(d)
-
- data_changed = MagicMock()
- viewer.model.dataChanged.connect(data_changed)
-
- # layoutChanged needs to be emitted for the new/removed columns to be
- # registered (dataChanged is not enough)
- layout_changed = MagicMock()
- viewer.model.layoutChanged.connect(layout_changed)
-
- assert data_changed.call_count == 0
- assert layout_changed.call_count == 0
- viewer.model.columnCount() == 2
-
- d.add_component([3, 4, 5, 6, 2], 'z')
-
- assert data_changed.call_count == 1
- assert layout_changed.call_count == 1
- viewer.model.columnCount() == 3
-
- d.remove_component(d.id['z'])
-
- assert data_changed.call_count == 2
- assert layout_changed.call_count == 2
- viewer.model.columnCount() == 2
-
-
-def test_table_title():
-
- app = get_qapp() # noqa
-
- data1 = Data(a=[1, 2, 3, 4, 5], label='test1')
- data2 = Data(a=[1, 2, 3, 4, 5], label='test2')
-
- dc = DataCollection([data1, data2])
-
- gapp = GlueApplication(dc)
-
- viewer = gapp.new_data_viewer(TableViewer)
-
- assert viewer.windowTitle() == 'Table'
-
- viewer.add_data(data1)
-
- assert viewer.windowTitle() == 'Table: test1'
-
- viewer.add_data(data2)
-
- assert viewer.windowTitle() == 'Table: test2'
-
-
-def test_add_subset():
-
- # Regression test for a bug that occurred when adding a subset
- # directly to the table viewer.
-
- data1 = Data(a=[1, 2, 3, 4, 5], label='test1')
- data2 = Data(a=[1, 2, 3, 4, 5], label='test2')
- dc = DataCollection([data1, data2])
- dc.new_subset_group('test subset 1', data1.id['a'] > 2)
-
- gapp = GlueApplication(dc)
-
- viewer = gapp.new_data_viewer(TableViewer)
- viewer.add_subset(data1.subsets[0])
-
- assert len(viewer.state.layers) == 2
- assert not viewer.state.layers[0].visible
- assert viewer.state.layers[1].visible
-
- dc.new_subset_group('test subset 2', data1.id['a'] <= 2)
-
- assert len(viewer.state.layers) == 3
- assert not viewer.state.layers[0].visible
- assert viewer.state.layers[1].visible
- assert viewer.state.layers[2].visible
-
- viewer.remove_subset(data1.subsets[1])
-
- assert len(viewer.state.layers) == 2
- assert not viewer.state.layers[0].visible
- assert viewer.state.layers[1].visible
-
- viewer.add_subset(data1.subsets[1])
-
- assert len(viewer.state.layers) == 3
- assert not viewer.state.layers[0].visible
- assert viewer.state.layers[1].visible
- assert viewer.state.layers[2].visible
-
- with pytest.raises(ValueError) as exc:
- viewer.add_subset(data2.subsets[1])
- assert exc.value.args[0] == 'subset parent data does not match existing table data'
-
-
-def test_graceful_close_after_invalid(capsys):
-
- # Regression test for a bug that caused an error if an invalid dataset
- # was added to the viewer after the user had acknowledged the error.
-
- d = Data(a=[[1, 2], [3, 4]], label='test')
-
- dc = DataCollection([d])
-
- gapp = GlueApplication(dc)
-
- viewer = gapp.new_data_viewer(TableViewer)
- gapp.show()
-
- process_events()
-
- with pytest.raises(ValueError, match='Can only use Table widget for 1D data'):
- viewer.add_data(d)
-
- viewer.close()
-
- process_events()
-
- # We use capsys here because the # error is otherwise only apparent in stderr.
- out, err = capsys.readouterr()
- assert out.strip() == ""
- assert err.strip() == ""
-
-
-def test_incompatible_subset():
-
- # Regression test for a bug that caused the table to be refreshed in an
- # infinite loop if incompatible subsets were present.
-
- data1 = Data(a=[1, 2, 3, 4, 5], label='test1')
- data2 = Data(a=[1, 2, 3, 4, 5], label='test2')
- dc = DataCollection([data1, data2])
-
- gapp = GlueApplication(dc)
-
- viewer = gapp.new_data_viewer(TableViewer)
- viewer.add_data(data1)
-
- dc.new_subset_group('test subset', data2.id['a'] > 2)
- gapp.show()
- process_events(0.5)
-
- with patch.object(viewer.layers[0], '_refresh') as refresh1:
- with patch.object(viewer.layers[1], '_refresh') as refresh2:
- process_events(0.5)
-
- assert refresh1.call_count == 0
- assert refresh2.call_count == 0
-
-
-@requires_pyqt_gt_59_or_pyside2
-def test_table_incompatible_attribute():
- """
- Regression test for a bug where the table viewer generates an
- uncaught IncompatibleAttribute error in _update_visible() if
- the dataset is not visible and an invalid subset exists at all.
- This occurred because layer_artists depending on
- invalid attributes were only being disabled (but were still
- visible) and the viewer attempts to compute a mask for
- all visible subsets if the underlying dataset is not visible.
- """
- app = get_qapp()
- d1 = Data(x=[1, 2, 3, 4], y=[5, 6, 7, 8], label='d1')
- d2 = Data(a=['a', 'b', 'c'], b=['x', 'y', 'z'], label='d2')
- dc = DataCollection([d1, d2])
- gapp = GlueApplication(dc)
- viewer = gapp.new_data_viewer(TableViewer)
- viewer.add_data(d2)
-
- # This subset should not be shown in the viewer
- sg1 = dc.new_subset_group('invalid', d1.id['x'] <= 3)
-
- gapp.show()
- process_events()
-
- assert len(viewer.layers) == 2
- assert not viewer.layers[1].visible
- assert viewer.layers[0].visible
-
- # This subset can be shown in the viewer
- sg2 = dc.new_subset_group('valid', d2.id['a'] == 'a')
-
- assert len(viewer.layers) == 3
- assert viewer.layers[2].visible
- assert not viewer.layers[1].visible
- assert viewer.layers[0].visible
-
- # The original IncompatibleAttribute was thrown
- # here as making the data layer invisible made
- # DataTableModel._update_visible() try and draw
- # the invalid subset
- viewer.layers[0].visible = False
- assert viewer.layers[2].visible
- assert not viewer.layers[1].visible
-
-
-def test_table_with_dask_column():
-
- da = pytest.importorskip('dask.array')
-
- app = get_qapp()
-
- d = Data(d=da.asarray([1, 2, 3, 4, 5]),
- e=np.arange(5) + 1)
-
- dc = DataCollection([d])
-
- gapp = GlueApplication(dc)
-
- widget = gapp.new_data_viewer(TableViewer)
- widget.add_data(d)
-
- sg1 = dc.new_subset_group('D <= 3', d.id['d'] <= 3)
- sg1.style.color = '#aa0000'
- sg2 = dc.new_subset_group('1 < E < 4', (d.id['e'] > 1) & (d.id['e'] < 4))
- sg2.style.color = '#0000cc'
-
- assert widget.state.layers[0].visible
- assert widget.state.layers[1].visible
- assert widget.state.layers[2].visible
-
- model = widget.ui.table.model()
-
- # We now check what the data and colors of the table are, and try various
- # sorting methods to make sure that things are still correct.
-
- data = {'d': [1, 2, 3, 4, 5],
- 'e': [1, 2, 3, 4, 5]}
-
- colors = ['#aa0000', '#380088', '#380088', None, None]
-
- check_values_and_color(model, data, colors)
-
- widget.state.layers[2].visible = False
-
- colors = ['#aa0000', '#aa0000', '#aa0000', None, None]
-
- check_values_and_color(model, data, colors)
-
-
-def test_table_preserve_model_after_selection():
-
- # Regression test for a bug that caused table viewers to return
- # to default sorting after a new subset was created with the row
- # selection tool. This occurred because the model was reset.
-
- app = get_qapp() # noqa
-
- d = Data(a=[1, 2, 3, 4, 5],
- b=[3.2, 1.2, 4.5, 3.3, 2.2],
- c=['e', 'b', 'c', 'a', 'f'], label='test')
-
- dc = DataCollection([d])
-
- gapp = GlueApplication(dc)
-
- viewer = gapp.new_data_viewer(TableViewer)
- viewer.add_data(d)
-
- model = viewer.ui.table.model()
-
- model.sort(1, Qt.AscendingOrder)
-
- data = {'a': [2, 5, 1, 4, 3],
- 'b': [1.2, 2.2, 3.2, 3.3, 4.5],
- 'c': ['b', 'f', 'e', 'a', 'c']}
- colors = [None for _ in range(5)]
-
- check_values_and_color(model, data, colors)
-
- # Create a new subset using the row selection tool
-
- subset_mode = gapp._session.edit_subset_mode
- subset_mode.edit_subset = None
- viewer.toolbar.actions['table:rowselect'].toggle()
-
- def press_key(key):
- event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, key, Qt.NoModifier)
- app.postEvent(viewer.ui.table, event)
- app.processEvents()
-
- # Select the second row
- press_key(Qt.Key_Tab)
- press_key(Qt.Key_Down)
- press_key(Qt.Key_Enter)
-
- process_events()
-
- # Check that the table model is still the same, which it
- # should be since we aren't changing the viewer Data
-
- post_model = viewer.ui.table.model()
- assert post_model == model
-
- # Check that the order is still the same
-
- color = d.subsets[0].style.color
- colors[1] = color
-
- check_values_and_color(post_model, data, colors)
-
-
-def test_table_widget_filter(tmpdir):
-
- # Test table interactions with filtering
-
- app = get_qapp() # noqa
-
- d = Data(a=[1, 2, 3, 4, 5],
- b=['cat', 'dog', 'cat', 'dog', 'fish'],
- c=['fluffy', 'rover', 'fluffball', 'spot', 'moby'], label='test')
-
- dc = DataCollection([d])
-
- gapp = GlueApplication(dc)
-
- widget = gapp.new_data_viewer(TableViewer)
- widget.add_data(d)
-
- widget.state.filter_att = d.components[2]
-
- widget.state.filter = 'cat'
- model = widget.ui.table.model()
-
- np.testing.assert_equal(model.filter_mask, [True, False, True, False, False])
-
- widget.state.filter_att = d.components[3]
- widget.state.filter = 'ff'
- np.testing.assert_equal(model.filter_mask, [True, False, True, False, False])
-
- # Test matching regular expressions
- widget.state.filter_att = d.components[3]
- widget.state.regex = True
-
- widget.state.filter = '^[a-z]{1}o'
- np.testing.assert_equal(model.filter_mask, [False, True, False, False, True])
-
- sg1 = dc.new_subset_group('test subset 1', d.id['a'] > 2)
- sg1.style.color = '#aa0000'
- data = {'a': [2, 5],
- 'b': ['dog', 'fish'],
- 'c': ['rover', 'moby']}
-
- colors = [None, '#aa0000']
-
- check_values_and_color(model, data, colors)
-
- widget.state.regex = False
- widget.state.filter = '^[a-z]{1}o'
- np.testing.assert_equal(model.filter_mask, [False, False, False, False, False])
-
- # Check that changing the filter disables the rowselect tool
- widget.toolbar.actions['table:rowselect'].toggle()
- process_events()
- widget.state.filter_att = d.components[2]
- assert widget.toolbar.active_tool is None
-
- # Check that disabling the full dataset means we only see the subset
- # This is a regression test since filtering originally broke this.
- widget.state.filter = ''
- for layer_artist in widget.layers:
- if layer_artist.visible and isinstance(layer_artist.layer, BaseData):
- layer_artist.visible = False
-
- data = {'a': [3, 4, 5],
- 'b': ['cat', 'dog', 'fish'],
- 'c': ['fluffball', 'spot', 'moby']}
-
- colors = ['#aa0000', '#aa0000', '#aa0000']
-
- check_values_and_color(model, data, colors)
-
- widget.state.filter_att = d.components[2]
- widget.state.filter = 'cat'
-
- data = {'a': [3],
- 'b': ['cat'],
- 'c': ['fluffball']}
-
- colors = ['#aa0000']
-
- check_values_and_color(model, data, colors)
-
-
-def test_table_widget_session_filter(tmpdir):
-
- # Test that filtering works with save/restore
-
- app = get_qapp() # noqa
-
- d = Data(a=[1, 2, 3, 4, 5],
- b=['cat', 'dog', 'cat', 'dog', 'fish'],
- c=['fluffy', 'rover', 'fluffball', 'spot', 'moby'], label='test')
-
- dc = DataCollection([d])
-
- gapp = GlueApplication(dc)
-
- widget = gapp.new_data_viewer(TableViewer)
- widget.add_data(d)
-
- widget.state.filter_att = d.components[2]
- widget.state.filter = 'cat'
- model = widget.ui.table.model()
-
- np.testing.assert_equal(model.filter_mask, [True, False, True, False, False])
-
- session_file = tmpdir.join('table.glu').strpath
-
- gapp.save_session(session_file)
-
- gapp2 = GlueApplication.restore_session(session_file)
- gapp2.show()
-
- d = gapp2.data_collection[0]
-
- widget2 = gapp2.viewers[0][0]
-
- model2 = widget2.ui.table.model()
-
- assert widget2.state.filter_att == d.components[2]
- assert widget2.state.filter == 'cat'
- np.testing.assert_equal(model2.filter_mask, [True, False, True, False, False])
diff --git a/glueviz.desktop b/glueviz.desktop
deleted file mode 100644
index d6472e50e..000000000
--- a/glueviz.desktop
+++ /dev/null
@@ -1,7 +0,0 @@
-[Desktop Entry]
-Type=Application
-Name=Glueviz
-Comment=Link visualizations of scientific datasets
-Exec=glue
-Icon=glueviz
-Categories=Education;Science;
diff --git a/glueviz.png b/glueviz.png
deleted file mode 100644
index 4c8e7cede..000000000
Binary files a/glueviz.png and /dev/null differ
diff --git a/setup.cfg b/setup.cfg
index 0a8f1edda..c94696d1b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -13,13 +13,9 @@ classifiers =
Programming Language :: Python :: 3.10
Topic :: Scientific/Engineering :: Visualization
License :: OSI Approved :: BSD License
-description = Multidimensional data visualization across files
+description = Core library for the glue multidimensional data visualization project
long_description = file: README.rst
-# NOTE: below we have to exclude ipykernel 5.0.0 and 5.1.0 below due to a bug
-# that caused issues in the IPython terminal. For more details:
-# https://github.com/ipython/ipykernel/pull/376
-
[options]
zip_safe = False
packages = find:
@@ -33,10 +29,7 @@ install_requires =
echo>=0.6
astropy>=4.0
setuptools>=30.3.0
- qtpy>=1.9
ipython>=4.0
- ipykernel>=4.0,!=5.0.0,!=5.1.0
- qtconsole>=4.3,!=5.4.2
dill>=0.2
h5py>=2.10; python_version<'3.11'
xlrd>=1.2
@@ -45,29 +38,22 @@ install_requires =
pvextractor>=0.2
importlib_resources>=1.3; python_version<'3.9'
importlib_metadata>=3.6; python_version<'3.10'
+ # For now, we include a dependency on glue-qt so that imports of the
+ # Qt-related functionality continue to work albeit with a deprecation
+ # warning. Once the deprecation phase is over, we can remove this
+ # dependency as well as all the compatibility imports.
+ glue-qt>=0.1.0
[options.entry_points]
glue.plugins =
- export_d3po = glue.plugins.export_d3po:setup
- pv_slicer = glue.plugins.tools.pv_slicer.qt:setup
coordinate_helpers = glue.plugins.coordinate_helpers:setup
wcs_autolinking = glue.plugins.wcs_autolinking:setup
dendro_factory = glue.plugins.dendro_viewer:setup
- dendro_viewer = glue.plugins.dendro_viewer.qt:setup
- image_viewer = glue.viewers.image.qt:setup
- scatter_viewer = glue.viewers.scatter.qt:setup
- histogram_viewer = glue.viewers.histogram.qt:setup
- profile_viewer = glue.viewers.profile.qt:setup
- table_viewer = glue.viewers.table.qt:setup
data_exporters = glue.core.data_exporters:setup
fits_format = glue.io.formats.fits:setup
export_python = glue.plugins.tools:setup
- directory_importer = glue.io.qt.directory_importer:setup
console_scripts =
glue-config = glue.config_gen:main
- glue-deps = glue._deps:main
-gui_scripts =
- glue = glue.main:main
[options.extras_require]
all =
@@ -81,19 +67,17 @@ all =
# for why we exclude pillow 7.1.0
pillow!=7.1.0
docs =
- sphinx
+ sphinx<7
sphinx-automodapi
sphinxcontrib-spelling
numpydoc
- sphinx-rtd-theme
+ sphinx-book-theme
astronomy =
PyAVM
astrodendro
spectral-cube
recommended =
scikit-image
-qt =
- PyQt5>=5.14
test =
pytest
pytest-cov
@@ -105,10 +89,6 @@ test =
[options.package_data]
* = *.png, *.ui, *.glu, *.hdf5, *.fits, *.xlsx, *.txt, *.csv, *.svg, *.vot
glue.core.data_factories.tests = data/*.jpg
-glue.viewers.histogram.qt.tests = data/*.glu
-glue.viewers.image.qt.tests = data/*.glu, baseline/*.png
-glue.viewers.profile.qt.tests = data/*.glu
-glue.viewers.scatter.qt.tests = data/*.glu
[flake8]
ignore = E226,E501,E731,F841,E127,E741,E402,W504,W605
@@ -124,17 +104,14 @@ filterwarnings =
ignore:DragAndDropTerminal._style_sheet_changed is deprecated
ignore:::ipykernel
ignore:Accessing zmq Socket attribute
- ignore:'U' mode is deprecated:DeprecationWarning:PyQt5
[coverage:run]
omit =
glue/*tests/*
- glue/qt/ui/*
glue/core/odict.py,
glue/core/glue_pickle.py
glue/external/*
*/glue/*tests/*
- */glue/qt/ui/*
*/glue/core/odict.py,
*/glue/core/glue_pickle.py
*/glue/external/*
diff --git a/tox.ini b/tox.ini
index e7ae8b735..2fe7aa9c8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
[tox]
envlist =
- py{38,39,310,311}-{codestyle,test,docs}-{pyqt514,pyqt515,pyside514,pyside515,pyqt63,pyside63}-all-{dev,legacy}
+ py{38,39,310,311}-{codestyle,test,docs}-all-{dev,legacy}
requires = pip >= 18.0
setuptools >= 30.3.0
@@ -9,9 +9,8 @@ requires = pip >= 18.0
passenv =
DISPLAY
HOME
-# Set to 1 to get more debug information from PyQt
setenv =
- test: QT_DEBUG_PLUGINS = 0
+ dev: PIP_EXTRA_INDEX_URL = https://pypi.anaconda.org/astropy/simple https://pypi.anaconda.org/scientific-python-nightly-wheels/simple
whitelist_externals =
find
rm
@@ -21,19 +20,12 @@ changedir =
test: .tmp/{envname}
docs: doc
deps =
- pyqt514: PyQt5==5.14.*
- pyqt515: PyQt5==5.15.*
- pyqt63: PyQt6==6.3.*
- pyqt64: PyQt6==6.4.*
- pyside514: PySide2==5.14.*
- pyside515: PySide2==5.15.*
- pyside63: PySide6==6.3.*
- pyside64: PySide6==6.4.*
- # Pin numpy-dev until #2353 is resolved
- dev: git+https://github.com/numpy/numpy@9b6a7b4f8
- dev: git+https://github.com/astropy/astropy
+ dev: numpy>=0.0.dev0
+ dev: astropy>=0.0.dev0
lts: astropy==5.0.*
lts: matplotlib==3.5.*
+ # Pin numpy-lts until permanent solution for #2353/#2428
+ lts: numpy==1.24.*
legacy: numpy==1.17.*
legacy: matplotlib==3.2.*
legacy: scipy==1.1.*
@@ -41,16 +33,13 @@ deps =
legacy: echo==0.5.*
legacy: astropy==4.0.*
legacy: setuptools==30.3.*
- legacy: qtpy==1.9.*
legacy: ipython==7.16.*
legacy: ipykernel==5.3.*
- legacy: qtconsole==4.3.*
legacy: dill==0.2.*
legacy: xlrd==1.2.*
legacy: h5py==2.10.*
legacy: mpl-scatter-density==0.7.*
legacy: openpyxl==3.0.*
- all: pytest-qt
extras =
test
all: all