Example #1
0
 def setup_method(self, method):
     self.data = Data(x=[1, 2, 3, 2, 2, 3, 1])
     figure = MagicMock()
     self.collect = DataCollection()
     self.client = HistogramClient(self.collect, figure)
     self.axes = self.client.axes
     self.hub = self.collect.hub
     self.connect()
Example #2
0
 def setup_method(self, method):
     self.data = Data(x=[0, 0, 0, 1, 2, 3, 3, 10, 20],
                      y=[-1, -1, -1, -2, -2, -2, -3, -5, -7])
     self.subset = self.data.new_subset()
     self.collect = DataCollection(self.data)
     self.client = HistogramClient(self.collect, FIGURE)
     self.axes = self.client.axes
     FIGURE.canvas.draw = MagicMock()
     assert FIGURE.canvas.draw.call_count == 0
Example #3
0
def load_data_files(datafiles):
    """Load data files and return a DataCollection"""
    from glue.core.data_collection import DataCollection
    from glue.core.data_factories import auto_data, load_data

    dc = DataCollection()
    for df in datafiles:
        dc.append(load_data(df, auto_data))
    return dc
Example #4
0
File: main.py Project: rguter/glue
def load_data_files(datafiles):
    """Load data files and return a DataCollection"""
    from glue.core.data_collection import DataCollection
    from glue.core.data_factories import auto_data, load_data

    dc = DataCollection()
    for df in datafiles:
        dc.append(load_data(df, auto_data))
    return dc
Example #5
0
 def setup_method(self, method):
     self.data = Data(y=[-1, -1, -1, -2, -2, -2, -3, -5, -7])
     self.data.add_component(
         CategoricalComponent(['a', 'a', 'a', 'b', 'c', 'd', 'd', 'e',
                               'f']), 'x')
     self.subset = self.data.new_subset()
     self.collect = DataCollection(self.data)
     self.client = HistogramClient(self.collect, FIGURE)
     self.axes = self.client.axes
     FIGURE.canvas.draw = MagicMock()
     assert FIGURE.canvas.draw.call_count == 0
Example #6
0
    def test_links(self):
        d1 = Data(label='x', x=[1, 2, 3])
        d2 = Data(label='y', y=[3, 4, 8])
        dc = DataCollection([d1, d2])
        link = ComponentLink([d1.id['x']], d2.id['y'], doubler)
        dc.add_link(link)

        np.testing.assert_array_equal(d1['y'], [2, 4, 6])

        app = GlueApplication(dc)
        self.check_clone(app)
Example #7
0
    def test_links(self):
        d1 = Data(label='x', x=[1, 2, 3])
        d2 = Data(label='y', y=[3, 4, 8])
        dc = DataCollection([d1, d2])
        link = ComponentLink([d1.id['x']], d2.id['y'], doubler)
        dc.add_link(link)

        np.testing.assert_array_equal(d1['y'], [2, 4, 6])

        app = GlueApplication(dc)
        self.check_clone(app)
Example #8
0
    def test_subset_groups_remain_synced_after_restore(self):
        # regrssion test for 352
        d = Data(label='hist', x=[[1, 2], [2, 3]])
        dc = DataCollection([d])
        dc.new_subset_group()
        app = GlueApplication(dc)

        app2 = clone(app)
        sg = app2.data_collection.subset_groups[0]
        assert sg.style.parent is sg

        sg.style.color = '#112233'
        assert sg.subsets[0].style.color == '#112233'
Example #9
0
    def test_subset_groups_remain_synced_after_restore(self):
        # regrssion test for 352
        d = Data(label='hist', x=[[1, 2], [2, 3]])
        dc = DataCollection([d])
        dc.new_subset_group()
        app = GlueApplication(dc)

        app2 = clone(app)
        sg = app2.data_collection.subset_groups[0]
        assert sg.style.parent is sg

        sg.style.color = '#112233'
        assert sg.subsets[0].style.color == '#112233'
Example #10
0
    def test_histogram(self):
        d = Data(label='hist', x=[[1, 2], [2, 3]])
        dc = DataCollection([d])

        app = GlueApplication(dc)
        w = app.new_data_viewer(HistogramViewer, data=d)
        self.check_clone(app)

        dc.new_subset_group()
        assert len(w.layers) == 2
        self.check_clone(app)

        w.nbins = 7
        self.check_clone(app)
Example #11
0
    def test_histogram(self):
        d = Data(label='hist', x=[[1, 2], [2, 3]])
        dc = DataCollection([d])

        app = GlueApplication(dc)
        w = app.new_data_viewer(HistogramWidget, data=d)
        self.check_clone(app)

        dc.new_subset_group()
        assert len(w.layers) == 2
        self.check_clone(app)

        w.nbins = 7
        self.check_clone(app)
Example #12
0
    def test_numerical_values_changed(self):

        # Here we slice two of the dimensions and then compare the results to a
        # manually sliced dataset.

        derived = IndexedData(self.data, (None, 2, None, 4, None))
        data_collection = DataCollection([self.data, derived])

        class CustomListener(HubListener):
            def __init__(self, hub):
                self.received = 0
                hub.subscribe(self,
                              NumericalDataChangedMessage,
                              handler=self.receive_message)

            def receive_message(self, message):
                self.received += 1

        listener = CustomListener(data_collection.hub)

        assert listener.received == 0

        derived.indices = (None, 3, None, 5, None)

        assert listener.received == 1

        derived.indices = (None, 3, None, 5, None)

        assert listener.received == 1
Example #13
0
    def test_scatter_viewer(self):
        d = Data(label='x', x=[1, 2, 3, 4, 5], y=[2, 3, 4, 5, 6])
        dc = DataCollection([d])
        app = GlueApplication(dc)
        w = app.new_data_viewer(ScatterViewer, data=d)
        self.check_clone(app)

        s1 = dc.new_subset_group()
        s2 = dc.new_subset_group()
        assert len(w.layers) == 3
        l1, l2, l3 = w.layers
        l1.zorder, l2.zorder = l2.zorder, l1.zorder
        l3.visible = False
        assert l3.visible is False
        copy = self.check_clone(app)
        assert copy.viewers[0][0].layers[-1].visible is False
Example #14
0
    def test_scatter_viewer(self):
        d = Data(label='x', x=[1, 2, 3, 4, 5], y=[2, 3, 4, 5, 6])
        dc = DataCollection([d])
        app = GlueApplication(dc)
        w = app.new_data_viewer(ScatterWidget, data=d)
        self.check_clone(app)

        s1 = dc.new_subset_group()
        s2 = dc.new_subset_group()
        assert len(w.layers) == 3
        l1, l2, l3 = w.layers
        l1.zorder, l2.zorder = l2.zorder, l1.zorder
        l3.visible = False
        assert l3.visible is False
        copy = self.check_clone(app)
        assert copy.viewers[0][0].layers[-1].visible is False
Example #15
0
 def setup_method(self, method):
     self.data = Data(x=[1, 2, 3, 2, 2, 3, 1])
     figure = MagicMock()
     self.collect = DataCollection()
     self.client = HistogramClient(self.collect, figure)
     self.axes = self.client.axes
     self.hub = self.collect.hub
     self.connect()
Example #16
0
 def setup_method(self, method):
     self.data = Data(y=[-1, -1, -1, -2, -2, -2, -3, -5, -7])
     self.data.add_component(CategoricalComponent(['a', 'a', 'a', 'b', 'c', 'd', 'd', 'e', 'f']), 'x')
     self.subset = self.data.new_subset()
     self.collect = DataCollection(self.data)
     self.client = HistogramClient(self.collect, FIGURE)
     self.axes = self.client.axes
     FIGURE.canvas.draw = MagicMock()
     assert FIGURE.canvas.draw.call_count == 0
Example #17
0
 def setup_method(self, method):
     self.data = Data(x=[0, 0, 0, 1, 2, 3, 3, 10, 20],
                      y=[-1, -1, -1, -2, -2, -2, -3, -5, -7])
     self.subset = self.data.new_subset()
     self.collect = DataCollection(self.data)
     self.client = HistogramClient(self.collect, FIGURE)
     self.axes = self.client.axes
     FIGURE.canvas.draw = MagicMock()
     assert FIGURE.canvas.draw.call_count == 0
Example #18
0
    def test_histogram(self):
        d = Data(label='hist', x=[[1, 2], [2, 3]])
        dc = DataCollection([d])

        app = GlueApplication(dc)
        w = app.new_data_viewer(HistogramViewer, data=d)
        copy1 = self.check_clone(app)

        dc.new_subset_group()
        assert len(w.layers) == 2
        copy2 = self.check_clone(app)

        w.nbins = 7
        copy3 = self.check_clone(app)

        app.close()
        copy1.close()
        copy2.close()
        copy3.close()
Example #19
0
    def test_multi_tab(self):
        d = Data(label='hist', x=[[1, 2], [2, 3]])
        dc = DataCollection([d])

        app = GlueApplication(dc)
        w1 = app.new_data_viewer(HistogramWidget, data=d)
        app.new_tab()
        w2 = app.new_data_viewer(HistogramWidget, data=d)
        assert app.viewers == ((w1, ), (w2, ))

        self.check_clone(app)
Example #20
0
    def __init__(self, application=None, data_collection=None,
                 command_stack=None, hub=None):

        self.application = application
        self.data_collection = data_collection or DataCollection()
        self.hub = self.data_collection.hub
        self.command_stack = command_stack or CommandStack()
        self.command_stack.session = self

        self.edit_subset_mode = EditSubsetMode()
        self.edit_subset_mode.data_collection = self.data_collection
Example #21
0
    def setup_method(self, method):
        self.data = example_data.test_data()
        self.ids = [
            self.data[0].find_component_id('a'),
            self.data[0].find_component_id('b'),
            self.data[1].find_component_id('c'),
            self.data[1].find_component_id('d')
        ]
        self.roi_limits = (0.5, 0.5, 1.5, 1.5)
        self.roi_points = (np.array([1]), np.array([1]))
        self.collect = DataCollection()
        EditSubsetMode().data_collection = self.collect

        self.hub = self.collect.hub

        FIGURE.clf()
        axes = FIGURE.add_subplot(111)
        self.client = ScatterClient(self.collect, axes=axes)

        self.connect()
Example #22
0
def main():

    app = QApplication(sys.argv)
    win = QMainWindow()

    data = example_data.simple_image()
    dc = DataCollection([data])
    histo_client = HistogramWidget(dc)

    hub = Hub(dc, histo_client)
    win.setCentralWidget(histo_client)
    win.show()
    sys.exit(app.exec_())
Example #23
0
    def __init__(self, application=None, data_collection=None,
                 command_stack=None, hub=None):

        # applications can be added after instantiation
        self.application = application

        self.data_collection = data_collection or DataCollection()
        self.hub = self.data_collection.hub
        self.command_stack = command_stack or CommandStack()
        self.command_stack.session = self

        # set the global data_collection for subset updates
        from glue.core.edit_subset_mode import EditSubsetMode
        EditSubsetMode().data_collection = self.data_collection
Example #24
0
def main():
    from glue.core.data import Data
    from glue.core.data_collection import DataCollection
    import numpy as np

    x = np.random.random((5, 5))
    y = x * 3
    data = DataCollection(Data(label='test', x=x, y=y))

    CustomComponentWidget.create_component(data)
    for d in data:
        print(d.label)
        for c in d.components:
            print('\t%s' % c)
Example #25
0
    def __init__(self, data_collection=None, session=None):
        if session is not None:
            self._session = session
            session.application = self
            self._data = session.data_collection
        else:
            self._data = data_collection or DataCollection()
            self._session = Session(data_collection=self._data,
                                    application=self)

        self._hub = self._session.hub
        self._cmds = self._session.command_stack
        self._cmds.add_callback(self._update_undo_redo_enabled)

        self._settings = {}
        for key, value, validator in settings:
            self._settings[key] = [value, validator]
Example #26
0
    def setup_method(self, method):
        self.data = example_data.test_data()
        self.ids = [self.data[0].find_component_id('a'),
                    self.data[0].find_component_id('b'),
                    self.data[1].find_component_id('c'),
                    self.data[1].find_component_id('d')]
        self.roi_limits = (0.5, 0.5, 1.5, 1.5)
        self.roi_points = (np.array([1]), np.array([1]))
        self.collect = DataCollection()
        EditSubsetMode().data_collection = self.collect

        self.hub = self.collect.hub

        FIGURE.clf()
        axes = FIGURE.add_subplot(111)
        self.client = ScatterClient(self.collect, axes=axes)

        self.connect()
Example #27
0
    def setup_method(self, method):
        self.data = example_data.test_categorical_data()
        self.ids = [
            self.data[0].find_component_id('x1'),
            self.data[0].find_component_id('y1'),
            self.data[1].find_component_id('x2'),
            self.data[1].find_component_id('y2')
        ]
        self.roi_limits = (0.5, 0.5, 4, 4)
        self.roi_points = (np.array([1]), np.array([3]))
        self.collect = DataCollection()
        self.hub = self.collect.hub

        FIGURE.clf()
        axes = FIGURE.add_subplot(111)
        self.client = ScatterClient(self.collect, axes=axes)

        self.connect()
Example #28
0
    def test_deselect_tool_on_viewer_change(self):

        d = Data(label='hist', x=[[1, 2], [2, 3]])
        dc = DataCollection([d])

        app = GlueApplication(dc)
        v1 = app.new_data_viewer(HistogramViewer, data=d)
        v2 = app.new_data_viewer(HistogramViewer, data=d)

        assert v1.toolbar.active_tool is None
        assert v2.toolbar.active_tool is None

        v2.toolbar.active_tool = 'select:xrange'

        assert v1.toolbar.active_tool is None
        assert v2.toolbar.active_tool.tool_id == 'select:xrange'

        app.current_tab.activateNextSubWindow()

        assert v1.toolbar.active_tool is None
        assert v2.toolbar.active_tool is None

        v1.toolbar.active_tool = 'select:xrange'

        # Emit a signal without changing the active subWindow to make sure that
        # the tool doesn't get reset.
        app.current_tab.subWindowActivated.emit(
            app.current_tab.activeSubWindow())

        assert v1.toolbar.active_tool.tool_id == 'select:xrange'
        assert v2.toolbar.active_tool is None

        app.current_tab.activateNextSubWindow()

        assert v1.toolbar.active_tool is None
        assert v2.toolbar.active_tool is None

        app.close()
Example #29
0
class TestHistogramClient(object):

    def setup_method(self, method):
        self.data = Data(x=[0, 0, 0, 1, 2, 3, 3, 10, 20],
                         y=[-1, -1, -1, -2, -2, -2, -3, -5, -7])
        self.subset = self.data.new_subset()
        self.collect = DataCollection(self.data)
        self.client = HistogramClient(self.collect, FIGURE)
        self.axes = self.client.axes
        FIGURE.canvas.draw = MagicMock()
        assert FIGURE.canvas.draw.call_count == 0

    def draw_count(self):
        return self.axes.figure.canvas.draw.call_count

    def layer_drawn(self, layer):
        return layer in self.client._artists and \
            all(a.visible for a in self.client._artists[layer]) and \
            all(len(a.artists) > 0 for a in self.client._artists[layer])

    def layer_present(self, layer):
        return layer in self.client._artists

    def assert_autoscaled(self):
        yra = self.client.axes.get_ylim()
        datara = [99999, -99999]
        for a in self.client._artists:
            if a.y.size > 0:
                datara[0] = min(datara[0], a.y.min())
                datara[1] = max(datara[1], a.y.max())

        assert yra[0] <= datara[0]
        assert yra[1] >= datara[1]

    def test_empty_on_creation(self):
        assert self.data not in self.client._artists

    def test_add_layer(self):
        self.client.add_layer(self.data)
        assert self.layer_present(self.data)
        assert not self.layer_drawn(self.data)

        self.client.set_component(self.data.components[0])
        assert self.layer_drawn(self.data)

    def test_add_invalid_layer_raises(self):
        self.collect.remove(self.data)
        with pytest.raises(IncompatibleDataException):
            self.client.add_layer(self.data)

    def test_add_subset_auto_adds_data(self):
        subset = self.data.new_subset()
        self.client.add_layer(subset)
        assert self.layer_present(self.data)
        assert self.layer_present(subset)

        self.client.set_component(self.data.components[0])
        assert self.layer_drawn(self.data)

    def test_double_add_ignored(self):
        self.client.add_layer(self.data)
        art = self.client._artists[self.data]
        self.client.add_layer(self.data)
        assert self.client._artists[self.data] == art

    def test_add_data_auto_adds_subsets(self):
        s = self.data.new_subset()
        self.client.add_layer(self.data)
        assert self.layer_present(s)

    def test_data_removal(self):
        self.client.add_layer(self.data)
        self.client.remove_layer(self.data)
        assert not (self.layer_present(self.data))

    def test_data_removal_removes_subsets(self):
        self.client.add_layer(self.data)
        self.client.remove_layer(self.data)
        self.data.new_subset()
        assert len(self.data.subsets) > 0

        for subset in self.data.subsets:
            assert not (self.layer_present(subset))

    def test_layer_updates_on_data_add(self):
        self.client.add_layer(self.data)
        for s in self.data.subsets:
            assert s in self.client._artists

    def test_set_component_updates_component(self):
        self.client.add_layer(self.data)
        comp = self.data.find_component_id('uniform')
        self.client.set_component(comp)
        assert self.client._component is comp

    def test_set_component_redraws(self):
        self.client.add_layer(self.data)
        comp = self.data.id['x']
        comp2 = self.data.id['y']
        self.client.set_component(comp)
        ct0 = self.draw_count()
        self.client.set_component(comp2)
        assert self.draw_count() > ct0

    def test_remove_not_present_ignored(self):
        self.client.remove_layer(self.data)

    def test_set_visible_external_data(self):
        self.client.set_layer_visible(None, False)

    def test_get_visible_external_data(self):
        assert not (self.client.is_layer_visible(None))

    def test_set_visible(self):
        self.client.add_layer(self.data)
        self.client.set_layer_visible(self.data, False)
        assert not (self.client.is_layer_visible(self.data))

    def test_draw_histogram_one_layer(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.find_component_id('uniform'))

    def test_draw_histogram_subset_hidden(self):
        self.client.add_layer(self.data)
        s = self.data.new_subset()
        self.client.set_layer_visible(s, False)
        self.client.set_component(self.data.find_component_id('uniform'))

    def test_draw_histogram_two_layers(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.find_component_id('uniform'))

    def test_update_property_set_triggers_redraw(self):
        self.client.add_layer(self.data)
        ct = self.draw_count()
        self.client.normed ^= True
        assert self.draw_count() > ct

    @pytest.mark.parametrize(('prop'), ['normed', 'cumulative'])
    def test_set_boolean_property(self, prop):
        """Boolean properties should sync with artists"""
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])

        setattr(self.client, prop, False)
        for a in self.client._artists:
            assert not getattr(a, prop)

        setattr(self.client, prop, True)
        for a in self.client._artists:
            assert getattr(a, prop)

    def test_set_nbins(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])

        self.client.nbins = 100
        for a in self.client._artists[self.data]:
            assert a.nbins == 100
            assert a.x.size == 100 + 1

    def test_autoscale(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])
        self.client.axes.set_ylim(0, .1)
        self.client.autoscale = False
        self.client.autoscale = True
        self.assert_autoscaled()

    def test_xlimits(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])

        self.client.xlimits = -12, 20
        assert self.client.xlimits == (-12, 20)
        for a in self.client._artists[self.data]:
            assert a.lo == -12
            assert a.hi == 20

    def test_set_xlimits_out_of_data_range(self):
        """Setting xlimits outside of range shouldn't crash"""
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])

        self.client.xlimits = 100, 200
        self.client.xlimits = -200, -100

    def test_component_property(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])
        assert self.client.component is self.data.components[0]

    def test_apply_roi(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['y'])
        # bins are -7...-1

        self.data.edit_subset = [self.data.subsets[0]]
        roi = PolygonalROI(vx=[-5.1, -4.5, -3.2], vy=[2, 3, 4])

        self.client.apply_roi(roi)
        state = self.data.subsets[0].subset_state
        assert isinstance(state, RangeSubsetState)

        # range should expand to nearest bin edge
        assert state.lo == -6
        assert state.hi == -3

    def test_apply_roi_xlog(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        self.data.edit_subset = [self.data.subsets[0]]
        self.client.xlog = True
        roi = PolygonalROI(vx=[1, 2, 3], vy=[2, 3, 4])

        self.client.apply_roi(roi)
        state = self.data.subsets[0].subset_state
        assert isinstance(state, RangeSubsetState)
        np.testing.assert_allclose(state.lo, 7.3680629972807736)
        np.testing.assert_allclose(state.hi, 1000)

    def test_xlimits_sticky_with_component(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])
        self.client.xlimits = 5, 6

        self.client.set_component(self.data.components[1])
        self.client.xlimits = 7, 8

        self.client.set_component(self.data.components[0])
        assert self.client.xlimits == (5, 6)

        self.client.set_component(self.data.components[1])
        assert self.client.xlimits == (7, 8)

    def test_default_xlimits(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        assert self.client.xlimits == (0, 20)
        self.client.set_component(self.data.id['y'])
        assert self.client.xlimits == (-7, -1)

    def test_xlimit_single_set(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])

        self.client.xlimits = (None, 5)
        assert self.client.xlimits == (0, 5)
        self.client.xlimits = (3, None)
        assert self.client.xlimits == (3, 5)

    def test_xlimit_reverse_set(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])

        self.client.xlimits = 5, 3
        assert self.client.xlimits == (3, 5)

    def test_xlog_axes_labels(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])

        self.client.xlog = True
        assert self.client.axes.get_xlabel() == 'Log x'

        self.client.xlog = False
        assert self.client.axes.get_xlabel() == 'x'

        self.client.ylog = True
        assert self.client.axes.get_ylabel() == 'N'

        self.client.ylog = False
        assert self.client.axes.get_ylabel() == 'N'

    def test_xlog_snaps_limits(self):

        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])

        self.client.axes.set_xlim((-1, 1))
        self.client.xlog = True
        assert self.client.axes.get_xlim() != (-1, 1)

    def test_artist_clear_resets_arrays(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])
        for a in self.client._artists[self.data]:
            assert a.get_data()[0].size > 0
            a.clear()
            assert a.get_data()[0].size == 0

    def test_component_replaced(self):
        # regression test for 508
        self.client.register_to_hub(self.collect.hub)
        self.client.add_layer(self.data)
        self.client.component = self.data.components[0]

        test = ComponentID('test')
        self.data.update_id(self.client.component, test)
        assert self.client.component is test

    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.

        self.client.add_layer(self.data)

        self.client.set_component(self.data.id['y'])
        self.client.xlimits = -20, 20
        self.client.nbins = 12

        y1 = self.client._artists[0]._y

        self.client.set_component(self.data.id['x'])
        self.client.xlimits = -20, 20
        self.client.nbins = 12

        y2 = self.client._artists[0]._y
        assert not np.allclose(y1, y2)

        self.client.set_component(self.data.id['y'])

        y3 = self.client._artists[0]._y
        np.testing.assert_allclose(y1, y3)
Example #30
0
class TestScatterClient(object):
    def setup_method(self, method):
        self.data = example_data.test_data()
        self.ids = [
            self.data[0].find_component_id('a'),
            self.data[0].find_component_id('b'),
            self.data[1].find_component_id('c'),
            self.data[1].find_component_id('d')
        ]
        self.roi_limits = (0.5, 0.5, 1.5, 1.5)
        self.roi_points = (np.array([1]), np.array([1]))
        self.collect = DataCollection()
        EditSubsetMode().data_collection = self.collect

        self.hub = self.collect.hub

        FIGURE.clf()
        axes = FIGURE.add_subplot(111)
        self.client = ScatterClient(self.collect, axes=axes)

        self.connect()

    def teardown_method(self, methdod):
        self.assert_properties_correct()
        self.assert_axes_ticks_correct()

    def assert_properties_correct(self):
        ax = self.client.axes
        cl = self.client
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()
        assert abs(cl.xmin - min(xlim)) < 1e-2
        assert abs(cl.xmax - max(xlim)) < 1e-2
        assert abs(cl.ymin - min(ylim)) < 1e-2
        assert abs(cl.ymax - max(ylim)) < 1e-2
        assert cl.xflip == (xlim[1] < xlim[0])
        assert cl.yflip == (ylim[1] < ylim[0])
        assert cl.xlog == (ax.get_xscale() == 'log')
        assert cl.ylog == (ax.get_yscale() == 'log')
        assert (self.client.xatt is None) or isinstance(
            self.client.xatt, ComponentID)
        assert (self.client.yatt is None) or isinstance(
            self.client.yatt, ComponentID)

    def check_ticks(self, axis, is_log, is_cat):
        locator = axis.get_major_locator()
        formatter = axis.get_major_formatter()
        if is_log:
            assert isinstance(locator, LogLocator)
            assert isinstance(formatter, LogFormatterMathtext)
        elif is_cat:
            assert isinstance(locator, MaxNLocator)
            assert isinstance(formatter, FuncFormatter)
        else:
            assert isinstance(locator, AutoLocator)
            assert isinstance(formatter, ScalarFormatter)

    def assert_axes_ticks_correct(self):
        ax = self.client.axes
        client = self.client
        if client.xatt is not None:
            self.check_ticks(ax.xaxis, client.xlog,
                             client._check_categorical(client.xatt))
        if client.yatt is not None:
            self.check_ticks(ax.yaxis, client.ylog,
                             client._check_categorical(client.yatt))

    def plot_data(self, layer):
        """ Return the data bounds for a given layer (data or subset)
        Output format: [xmin, xmax], [ymin, ymax]
        """
        client = self.client
        x, y = client.artists[layer][0].get_data()
        xmin = x.min()
        xmax = x.max()
        ymin = y.min()
        ymax = y.max()
        return [xmin, xmax], [ymin, ymax]

    def plot_limits(self):
        """ Return the plot limits
        Output format [xmin, xmax], [ymin, ymax]
        """
        ax = self.client.axes
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()
        return (min(xlim), max(xlim)), (min(ylim), max(ylim))

    def assert_layer_inside_limits(self, layer):
        """Assert that points of a layer are within plot limits """
        xydata = self.plot_data(layer)
        xylimits = self.plot_limits()
        assert xydata[0][0] >= xylimits[0][0]
        assert xydata[1][0] >= xylimits[1][0]
        assert xydata[0][1] <= xylimits[0][1]
        assert xydata[1][1] <= xylimits[1][1]

    def setup_2d_data(self):
        d = Data(x=[[1, 2], [3, 4]], y=[[2, 4], [6, 8]])
        self.collect.append(d)
        self.client.add_layer(d)
        self.client.xatt = d.id['x']
        self.client.yatt = d.id['y']
        return d

    def add_data(self, data=None):
        if data is None:
            data = self.data[0]
        data.edit_subset = data.new_subset()
        self.collect.append(data)
        self.client.add_data(data)
        return data

    def add_data_and_attributes(self):
        data = self.add_data()
        data.edit_subset = data.new_subset()
        self.client.xatt = self.ids[0]
        self.client.yatt = self.ids[1]
        return data

    def is_first_in_front(self, front, back):
        z1 = self.client.get_layer_order(front)
        z2 = self.client.get_layer_order(back)
        return z1 > z2

    def connect(self):
        self.client.register_to_hub(self.hub)
        self.collect.register_to_hub(self.hub)

    def layer_drawn(self, layer):
        return self.client.is_layer_present(layer) and \
            all(a.enabled and a.visible for a in self.client.artists[layer])

    def layer_data_correct(self, layer, x, y):
        xx, yy = self.client.artists[layer][0].get_data()
        if max(abs(xx - x)) > .01:
            return False
        if max(abs(yy - y)) > .01:
            return False
        return True

    def test_empty_on_creation(self):
        for d in self.data:
            assert not self.client.is_layer_present(d)

    def test_add_external_data_raises_exception(self):
        data = Data()
        with pytest.raises(TypeError) as exc:
            self.client.add_data(data)
        assert exc.value.args[0] == "Layer not in data collection"

    def test_valid_add(self):
        self.add_data()
        assert self.client.is_layer_present(self.data[0])

    def test_axis_labels_sync_with_setters(self):
        self.add_data()
        self.client.xatt = self.ids[1]
        assert self.client.axes.get_xlabel() == self.ids[1].label
        self.client.yatt = self.ids[0]
        assert self.client.axes.get_ylabel() == self.ids[0].label

    def test_setters_require_componentID(self):
        self.add_data()
        with pytest.raises(TypeError):
            self.client.xatt = self.ids[1]._label
        self.client.xatt = self.ids[1]

    def test_logs(self):
        self.add_data()
        self.client.xlog = True
        assert self.client.axes.get_xscale() == 'log'

        self.client.xlog = False
        assert self.client.axes.get_xscale() == 'linear'

        self.client.ylog = True
        assert self.client.axes.get_yscale() == 'log'

        self.client.ylog = False
        assert self.client.axes.get_yscale() == 'linear'

    def test_flips(self):
        self.add_data()

        self.client.xflip = True
        self.assert_flips(True, False)

        self.client.xflip = False
        self.assert_flips(False, False)

        self.client.yflip = True
        self.assert_flips(False, True)

        self.client.yflip = False
        self.assert_flips(False, False)

    def assert_flips(self, xflip, yflip):
        ax = self.client.axes
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()
        assert (xlim[1] < xlim[0]) == xflip
        assert (ylim[1] < ylim[0]) == yflip

    def test_double_add(self):
        n0 = len(self.client.axes.lines)
        layer = self.add_data_and_attributes()
        # data present
        assert len(self.client.axes.lines) == n0 + 1 + len(layer.subsets)
        layer = self.add_data()
        # data still present
        assert len(self.client.axes.lines) == n0 + 1 + len(layer.subsets)

    def test_data_updates_propagate(self):
        layer = self.add_data_and_attributes()
        assert self.layer_drawn(layer)
        self.client._layer_updated = False
        layer.style.color = 'k'
        assert self.client._layer_updated

    def test_data_removal(self):
        layer = self.add_data()
        subset = layer.new_subset()
        self.collect.remove(layer)
        assert not self.client.is_layer_present(layer)
        assert not self.client.is_layer_present(subset)

    def test_add_subset_while_connected(self):
        layer = self.add_data()
        subset = layer.new_subset()
        assert self.client.is_layer_present(subset)

    def test_subset_removal(self):
        layer = self.add_data()
        subset = layer.new_subset()
        assert self.client.is_layer_present(layer)
        subset.delete()
        assert not self.client.is_layer_present(subset)

    def test_subset_removal_removes_from_plot(self):
        layer = self.add_data_and_attributes()
        subset = layer.new_subset()
        ct0 = len(self.client.axes.lines)
        subset.delete()
        assert len(self.client.axes.lines) == ct0 - 1

    def test_add_subset_to_untracked_data(self):
        subset = self.data[0].new_subset()
        assert not self.client.is_layer_present(subset)

    def test_valid_plot_data(self):
        layer = self.add_data_and_attributes()
        x = layer[self.ids[0]]
        y = layer[self.ids[1]]
        assert self.layer_data_correct(layer, x, y)

    def test_attribute_update_plot_data(self):
        layer = self.add_data_and_attributes()
        x = layer[self.ids[0]]
        y = layer[self.ids[0]]
        self.client.yatt = self.ids[0]
        assert self.layer_data_correct(layer, x, y)

    def test_invalid_plot(self):
        layer = self.add_data_and_attributes()
        assert self.layer_drawn(layer)
        c = ComponentID('bad id')
        self.client.xatt = c
        assert not self.layer_drawn(layer)
        self.client.xatt = self.ids[0]

    def test_redraw_called_on_invalid_plot(self):
        """ Plot should be updated when given invalid data,
        to sync layers' disabled/invisible states"""
        ctr = MagicMock()
        layer = self.add_data_and_attributes()
        assert self.layer_drawn(layer)
        c = ComponentID('bad id')
        self.client._redraw = ctr
        ct0 = ctr.call_count
        self.client.xatt = c
        ct1 = ctr.call_count
        ncall = ct1 - ct0
        expected = len(self.client.artists)
        assert ncall >= expected
        self.client.xatt = self.ids[0]

    def test_two_incompatible_data(self):
        d0 = self.add_data(self.data[0])
        d1 = self.add_data(self.data[1])
        self.client.xatt = self.ids[0]
        self.client.yatt = self.ids[1]
        x = d0[self.ids[0]]
        y = d0[self.ids[1]]
        assert self.layer_drawn(d0)
        assert self.layer_data_correct(d0, x, y)
        assert not self.layer_drawn(d1)

        self.client.xatt = self.ids[2]
        self.client.yatt = self.ids[3]
        x = d1[self.ids[2]]
        y = d1[self.ids[3]]
        assert self.layer_drawn(d1)
        assert self.layer_data_correct(d1, x, y)
        assert not self.layer_drawn(d0)

    def test_subsets_connect_with_data(self):
        data = self.data[0]
        s1 = data.new_subset()
        s2 = data.new_subset()
        self.collect.append(data)
        self.client.add_data(data)
        assert self.client.is_layer_present(s1)
        assert self.client.is_layer_present(s2)
        assert self.client.is_layer_present(data)

        # should also work with add_layer
        self.collect.remove(data)
        assert data not in self.collect
        assert not self.client.is_layer_present(s1)
        self.collect.append(data)
        self.client.add_layer(data)
        assert self.client.is_layer_present(s1)

    def test_edit_subset_connect_with_data(self):
        data = self.add_data()
        assert self.client.is_layer_present(data.edit_subset)

    def test_edit_subset_removed_with_data(self):
        data = self.add_data()
        self.collect.remove(data)
        assert not self.client.is_layer_present(data.edit_subset)

    def test_apply_roi(self):
        data = self.add_data_and_attributes()
        roi = RectangularROI()
        roi.update_limits(*self.roi_limits)
        x, y = self.roi_points
        self.client.apply_roi(roi)
        assert self.layer_data_correct(data.edit_subset, x, y)

    def test_apply_roi_adds_on_empty(self):
        data = self.add_data_and_attributes()
        data._subsets = []
        data.edit_subset = None
        roi = RectangularROI()
        roi.update_limits(*self.roi_limits)
        x, y = self.roi_points
        self.client.apply_roi(roi)
        assert data.edit_subset is not None

    def test_apply_roi_applies_to_all_editable_subsets(self):
        d1 = self.add_data_and_attributes()
        d2 = self.add_data()
        state1 = d1.edit_subset.subset_state
        state2 = d2.edit_subset.subset_state
        roi = RectangularROI()
        roi.update_limits(*self.roi_limits)
        x, y = self.roi_points
        self.client.apply_roi(roi)
        assert d1.edit_subset.subset_state is not state1
        assert d1.edit_subset.subset_state is not state2

    def test_apply_roi_doesnt_add_if_any_selection(self):
        d1 = self.add_data_and_attributes()
        d2 = self.add_data()
        d1.edit_subset = None
        d2.edit_subset = d2.new_subset()
        ct = len(d1.subsets)
        roi = RectangularROI()
        roi.update_limits(*self.roi_limits)
        x, y = self.roi_points
        self.client.apply_roi(roi)
        assert len(d1.subsets) == ct

    def test_subsets_drawn_over_data(self):
        data = self.add_data_and_attributes()
        subset = data.new_subset()
        assert self.is_first_in_front(subset, data)

    def test_log_sticky(self):
        self.add_data_and_attributes()
        self.assert_logs(False, False)

        self.client.xlog = True
        self.client.ylog = True
        self.assert_logs(True, True)

        self.client.xatt = self.ids[1]
        self.client.yatt = self.ids[0]
        self.assert_logs(True, True)

    def test_log_ticks(self):
        # regression test for 354
        self.add_data_and_attributes()
        self.assert_logs(False, False)

        self.client.xlog = True

        self.client.yatt = self.ids[0]

        self.assert_logs(True, False)
        assert not isinstance(self.client.axes.yaxis.get_major_locator(),
                              LogLocator)

    def assert_logs(self, xlog, ylog):
        ax = self.client.axes
        assert ax.get_xscale() == ('log' if xlog else 'linear')
        assert ax.get_yscale() == ('log' if ylog else 'linear')

    def test_flip_sticky(self):
        self.add_data_and_attributes()
        self.client.xflip = True
        self.assert_flips(True, False)
        self.client.xatt = self.ids[1]
        self.assert_flips(True, False)
        self.client.xatt = self.ids[0]
        self.assert_flips(True, False)

    def test_visibility_sticky(self):
        data = self.add_data_and_attributes()
        roi = RectangularROI()
        roi.update_limits(*self.roi_limits)
        assert self.client.is_visible(data.edit_subset)
        self.client.apply_roi(roi)
        self.client.set_visible(data.edit_subset, False)
        assert not self.client.is_visible(data.edit_subset)
        self.client.apply_roi(roi)
        assert not self.client.is_visible(data.edit_subset)

    def test_2d_data(self):
        """Should be abple to plot 2d data"""
        data = self.setup_2d_data()
        assert self.layer_data_correct(data, [1, 2, 3, 4], [2, 4, 6, 8])

    def test_2d_data_limits_with_subset(self):
        """visible limits should work with subsets and 2d data"""
        d = self.setup_2d_data()
        state = d.id['x'] > 2
        s = d.new_subset()
        s.subset_state = state
        assert self.client._visible_limits(0) == (1, 4)
        assert self.client._visible_limits(1) == (2, 8)

    def test_limits_nans(self):
        d = Data()
        x = Component(np.array([[1, 2], [np.nan, 4]]))
        y = Component(np.array([[2, 4], [np.nan, 8]]))
        xid = d.add_component(x, 'x')
        yid = d.add_component(y, 'y')
        self.collect.append(d)
        self.client.add_layer(d)
        self.client.xatt = xid
        self.client.yatt = yid

        assert self.client._visible_limits(0) == (1, 4)
        assert self.client._visible_limits(1) == (2, 8)

    def test_limits_inf(self):
        d = Data()
        x = Component(np.array([[1, 2], [np.infty, 4]]))
        y = Component(np.array([[2, 4], [-np.infty, 8]]))
        xid = d.add_component(x, 'x')
        yid = d.add_component(y, 'y')
        self.collect.append(d)
        self.client.add_layer(d)
        self.client.xatt = xid
        self.client.yatt = yid

        assert self.client._visible_limits(0) == (1, 4)
        assert self.client._visible_limits(1) == (2, 8)

    def test_xlog_relimits_if_negative(self):
        self.add_data_and_attributes()
        self.client.xflip = False
        self.client.xlog = False

        self.client.axes.set_xlim(-5, 5)
        self.client.xlog = True
        assert self.client.axes.get_xlim()[0] > .9

    def test_ylog_relimits_if_negative(self):
        self.add_data_and_attributes()
        self.client.yflip = False
        self.client.ylog = False
        self.client.axes.set_ylim(-5, 5)

        self.client.ylog = True
        assert self.client.axes.get_ylim()[0] > .9

    def test_subset_added_only_if_data_layer_present(self):
        self.collect.append(self.data[0])
        assert self.data[0] not in self.client.artists
        s = self.data[0].new_subset()
        assert s not in self.client.artists

    def test_pull_properties(self):
        ax = self.client.axes
        ax.set_xlim(6, 5)
        ax.set_ylim(8, 7)
        ax.set_xscale('log')
        ax.set_yscale('log')

        self.client._pull_properties()
        self.assert_properties_correct()

    def test_rescaled_on_init(self):
        layer = self.setup_2d_data()
        self.assert_layer_inside_limits(layer)

    def test_set_limits(self):
        self.client.xmin = 3
        self.client.xmax = 4
        self.client.ymin = 5
        self.client.ymax = 6
        ax = self.client.axes
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()

        assert xlim[0] == self.client.xmin
        assert xlim[1] == self.client.xmax
        assert ylim[0] == self.client.ymin
        assert ylim[1] == self.client.ymax

    def test_ignore_duplicate_updates(self):
        """Need not create new artist on every draw. Enforce this"""
        layer = self.setup_2d_data()

        m = MagicMock()
        self.client.artists[layer][0].clear = m

        self.client._update_layer(layer)
        ct0 = m.call_count

        self.client._update_layer(layer)
        ct1 = m.call_count

        assert ct1 == ct0

    def test_range_rois_preserved(self):
        data = self.add_data_and_attributes()
        assert self.client.xatt is not self.client.yatt

        roi = XRangeROI()
        roi.set_range(1, 2)
        self.client.apply_roi(roi)
        assert isinstance(data.edit_subset.subset_state, RangeSubsetState)
        assert data.edit_subset.subset_state.att == self.client.xatt

        roi = RectangularROI()
        roi = YRangeROI()
        roi.set_range(1, 2)
        self.client.apply_roi(roi)
        assert data.edit_subset.subset_state.att == self.client.yatt

    def test_component_replaced(self):
        # regression test for #508
        data = self.add_data_and_attributes()
        test = ComponentID('test')
        data.update_id(self.client.xatt, test)
        assert self.client.xatt is test
Example #31
0
                            data.hub.broadcast(msg)
                else:
                    pc = ParsedCommand(self._state[data][cid_new]['equation']._cmd, components)
                    link = ParsedComponentLink(cid_new, pc)
                    data.add_component_link(link)

            # Findally, reorder components as needed
            data.reorder_components(cids_all)

        super(ArithmeticEditorWidget, self).accept()


if __name__ == "__main__":  # pragma: nocover

    from glue.utils.qt import get_qapp
    app = get_qapp()

    import numpy as np

    from glue.core.data import Data
    from glue.core.data_collection import DataCollection

    x = np.random.random((5, 5))
    y = x * 3
    dc = DataCollection()
    dc.append(Data(label='test1', x=x, y=y))
    dc.append(Data(label='test2', a=x, b=y))

    widget = ArithmeticEditorWidget(dc)
    widget.exec_()
Example #32
0
        hub.subscribe(self,                     # subscribing object
                      DataMessage, # message type to subscribe to
                      handler = self.receive_message) # method to call


    def receive_message(self, message):
        """ Receives each DataMessage relay """
        print "    MyClient received a message \n"


# create objects
hub = Hub()
client = MyClient()
data = Data()
subset = data.new_subset()
data_collection = DataCollection()

# connect them to each other
data_collection.append(data)
data_collection.register_to_hub(hub)
client.register_to_hub(hub)

# manually send a DataMessage. Relayed to MyClient
print 'Manually sending DataMessage'
message = DataMessage(data)
hub.broadcast(message)

#modify the data object. Automatically generates a DataMessage
print 'Automatically triggering DataMessage'
data.label = "New label"
Example #33
0
class TestCategoricalHistogram(TestHistogramClient):

    def setup_method(self, method):
        self.data = Data(y=[-1, -1, -1, -2, -2, -2, -3, -5, -7])
        self.data.add_component(CategoricalComponent(['a', 'a', 'a', 'b', 'c', 'd', 'd', 'e', 'f']), 'x')
        self.subset = self.data.new_subset()
        self.collect = DataCollection(self.data)
        self.client = HistogramClient(self.collect, FIGURE)
        self.axes = self.client.axes
        FIGURE.canvas.draw = MagicMock()
        assert FIGURE.canvas.draw.call_count == 0

    def test_xlimit_single_set(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])

        self.client.xlimits = (None, 5)
        assert self.client.xlimits == (-0.5, 5)
        self.client.xlimits = (3, None)
        assert self.client.xlimits == (3, 5)

    def test_default_xlimits(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        assert self.client.xlimits == (-0.5, 5.5)
        self.client.set_component(self.data.id['y'])
        assert self.client.xlimits == (-7, -1)

    def test_change_default_bins(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        assert self.client.nbins == 6

    def test_tick_labels(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        correct_labels = ['a', 'b', 'c', 'd', 'e', 'f']
        formatter = self.client.axes.xaxis.get_major_formatter()
        xlabels = [formatter.format_data(pos) for pos in range(6)]
        assert correct_labels == xlabels

    def test_apply_roi(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        # bins are 1...4

        self.data.edit_subset = [self.data.subsets[0]]

        roi = MagicMock()
        roi.to_polygon.return_value = [1.2, 2, 4], [2, 3, 4]

        self.client.apply_roi(roi)
        state = self.data.subsets[0].subset_state
        assert isinstance(state, CategoricalROISubsetState)
        np.testing.assert_equal(self.data.subsets[0].subset_state.roi.categories,
                                np.array(['b', 'c', 'd', 'e']))

    # REMOVED TESTS
    def test_xlog_axes_labels(self):
        """ log-scale doesn't make sense for categorical data"""
        pass

    def test_xlog_snaps_limits(self):
        """ log-scale doesn't make sense for categorical data"""
        pass

    def test_apply_roi_xlog(self):
        """ log-scale doesn't make sense for categorical data"""
        pass

    def test_nbin_override_persists_over_attribute_change(self):
        # regression test for #398
        self.collect.append(self.data)
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        self.client.nbins = 7
        self.client.set_component(self.data.id['y'])
        assert self.client.nbins == 7
Example #34
0
class TestCommunication(object):

    def setup_method(self, method):
        self.data = Data(x=[1, 2, 3, 2, 2, 3, 1])
        figure = MagicMock()
        self.collect = DataCollection()
        self.client = HistogramClient(self.collect, figure)
        self.axes = self.client.axes
        self.hub = self.collect.hub
        self.connect()

    def draw_count(self):
        return self.axes.figure.canvas.draw.call_count

    def connect(self):
        self.client.register_to_hub(self.hub)
        self.collect.register_to_hub(self.hub)

    def test_ignore_data_add_message(self):
        self.collect.append(self.data)
        assert not (self.client.layer_present(self.data))

    def test_update_data_ignored_if_data_not_present(self):
        self.collect.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.collect.append(self.data)
        self.client.add_layer(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.collect.append(self.data)
        sub = self.data.new_subset()
        assert not (self.client.layer_present(sub))

    def test_add_subset_processed_if_data_present(self):
        self.collect.append(self.data)
        self.client.add_layer(self.data)
        sub = self.data.new_subset()
        assert (self.client.layer_present(sub))

    def test_update_subset_ignored_if_not_present(self):
        self.collect.append(self.data)
        self.client.add_layer(self.data)
        sub = self.data.new_subset()
        self.client.remove_layer(sub)
        ct0 = self.draw_count()
        sub.style.color = 'blue'
        assert self.draw_count() == ct0

    def test_update_subset_processed_if_present(self):
        self.collect.append(self.data)
        self.client.add_layer(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.collect.append(self.data)
        self.client.add_layer(self.data)
        self.collect.remove(self.data)
        assert not self.client.layer_present(self.data)

    def test_subset_remove_message(self):
        self.collect.append(self.data)
        self.client.add_layer(self.data)
        sub = self.data.new_subset()
        assert self.client.layer_present(sub)
        sub.delete()
        assert not self.client.layer_present(sub)
Example #35
0
class TestHistogramClient(object):
    def setup_method(self, method):
        self.data = Data(x=[0, 0, 0, 1, 2, 3, 3, 10, 20],
                         y=[-1, -1, -1, -2, -2, -2, -3, -5, -7])
        self.subset = self.data.new_subset()
        self.collect = DataCollection(self.data)
        self.client = HistogramClient(self.collect, FIGURE)
        self.axes = self.client.axes
        FIGURE.canvas.draw = MagicMock()
        assert FIGURE.canvas.draw.call_count == 0

    def draw_count(self):
        return self.axes.figure.canvas.draw.call_count

    def layer_drawn(self, layer):
        return layer in self.client._artists and \
            all(a.visible for a in self.client._artists[layer]) and \
            all(len(a.artists) > 0 for a in self.client._artists[layer])

    def layer_present(self, layer):
        return layer in self.client._artists

    def assert_autoscaled(self):
        yra = self.client.axes.get_ylim()
        datara = [99999, -99999]
        for a in self.client._artists:
            if a.y.size > 0:
                datara[0] = min(datara[0], a.y.min())
                datara[1] = max(datara[1], a.y.max())

        assert yra[0] <= datara[0]
        assert yra[1] >= datara[1]

    def test_empty_on_creation(self):
        assert self.data not in self.client._artists

    def test_add_layer(self):
        self.client.add_layer(self.data)
        assert self.layer_present(self.data)
        assert not self.layer_drawn(self.data)

        self.client.set_component(self.data.components[0])
        assert self.layer_drawn(self.data)

    def test_add_invalid_layer_raises(self):
        self.collect.remove(self.data)
        with pytest.raises(IncompatibleDataException):
            self.client.add_layer(self.data)

    def test_add_subset_auto_adds_data(self):
        subset = self.data.new_subset()
        self.client.add_layer(subset)
        assert self.layer_present(self.data)
        assert self.layer_present(subset)

        self.client.set_component(self.data.components[0])
        assert self.layer_drawn(self.data)

    def test_double_add_ignored(self):
        self.client.add_layer(self.data)
        art = self.client._artists[self.data]
        self.client.add_layer(self.data)
        assert self.client._artists[self.data] == art

    def test_add_data_auto_adds_subsets(self):
        s = self.data.new_subset()
        self.client.add_layer(self.data)
        assert self.layer_present(s)

    def test_data_removal(self):
        self.client.add_layer(self.data)
        self.client.remove_layer(self.data)
        assert not (self.layer_present(self.data))

    def test_data_removal_removes_subsets(self):
        self.client.add_layer(self.data)
        self.client.remove_layer(self.data)
        self.data.new_subset()
        assert len(self.data.subsets) > 0

        for subset in self.data.subsets:
            assert not (self.layer_present(subset))

    def test_layer_updates_on_data_add(self):
        self.client.add_layer(self.data)
        for s in self.data.subsets:
            assert s in self.client._artists

    def test_set_component_updates_component(self):
        self.client.add_layer(self.data)
        comp = self.data.find_component_id('uniform')
        self.client.set_component(comp)
        assert self.client._component is comp

    def test_set_component_redraws(self):
        self.client.add_layer(self.data)
        comp = self.data.id['x']
        comp2 = self.data.id['y']
        self.client.set_component(comp)
        ct0 = self.draw_count()
        self.client.set_component(comp2)
        assert self.draw_count() > ct0

    def test_remove_not_present_ignored(self):
        self.client.remove_layer(self.data)

    def test_set_visible_external_data(self):
        self.client.set_layer_visible(None, False)

    def test_get_visible_external_data(self):
        assert not (self.client.is_layer_visible(None))

    def test_set_visible(self):
        self.client.add_layer(self.data)
        self.client.set_layer_visible(self.data, False)
        assert not (self.client.is_layer_visible(self.data))

    def test_draw_histogram_one_layer(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.find_component_id('uniform'))

    def test_draw_histogram_subset_hidden(self):
        self.client.add_layer(self.data)
        s = self.data.new_subset()
        self.client.set_layer_visible(s, False)
        self.client.set_component(self.data.find_component_id('uniform'))

    def test_draw_histogram_two_layers(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.find_component_id('uniform'))

    def test_update_property_set_triggers_redraw(self):
        self.client.add_layer(self.data)
        ct = self.draw_count()
        self.client.normed ^= True
        assert self.draw_count() > ct

    @pytest.mark.parametrize(('prop'), ['normed', 'cumulative'])
    def test_set_boolean_property(self, prop):
        """Boolean properties should sync with artists"""
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])

        setattr(self.client, prop, False)
        for a in self.client._artists:
            assert not getattr(a, prop)

        setattr(self.client, prop, True)
        for a in self.client._artists:
            assert getattr(a, prop)

    def test_set_nbins(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])

        self.client.nbins = 100
        for a in self.client._artists[self.data]:
            assert a.nbins == 100
            assert a.x.size == 100 + 1

    def test_autoscale(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])
        self.client.axes.set_ylim(0, .1)
        self.client.autoscale = False
        self.client.autoscale = True
        self.assert_autoscaled()

    def test_xlimits(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])

        self.client.xlimits = -12, 20
        assert self.client.xlimits == (-12, 20)
        for a in self.client._artists[self.data]:
            assert a.lo == -12
            assert a.hi == 20

    def test_set_xlimits_out_of_data_range(self):
        """Setting xlimits outside of range shouldn't crash"""
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])

        self.client.xlimits = 100, 200
        self.client.xlimits = -200, -100

    def test_component_property(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])
        assert self.client.component is self.data.components[0]

    def test_apply_roi(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['y'])
        # bins are -7...-1

        self.data.edit_subset = [self.data.subsets[0]]
        roi = PolygonalROI(vx=[-5.1, -4.5, -3.2], vy=[2, 3, 4])

        self.client.apply_roi(roi)
        state = self.data.subsets[0].subset_state
        assert isinstance(state, RangeSubsetState)

        # range should expand to nearest bin edge
        assert state.lo == -6
        assert state.hi == -3

    def test_apply_roi_xlog(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        self.data.edit_subset = [self.data.subsets[0]]
        self.client.xlog = True
        roi = PolygonalROI(vx=[1, 2, 3], vy=[2, 3, 4])

        self.client.apply_roi(roi)
        state = self.data.subsets[0].subset_state
        assert isinstance(state, RangeSubsetState)
        np.testing.assert_allclose(state.lo, 7.3680629972807736)
        np.testing.assert_allclose(state.hi, 1000)

    def test_xlimits_sticky_with_component(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])
        self.client.xlimits = 5, 6

        self.client.set_component(self.data.components[1])
        self.client.xlimits = 7, 8

        self.client.set_component(self.data.components[0])
        assert self.client.xlimits == (5, 6)

        self.client.set_component(self.data.components[1])
        assert self.client.xlimits == (7, 8)

    def test_default_xlimits(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        assert self.client.xlimits == (0, 20)
        self.client.set_component(self.data.id['y'])
        assert self.client.xlimits == (-7, -1)

    def test_xlimit_single_set(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])

        self.client.xlimits = (None, 5)
        assert self.client.xlimits == (0, 5)
        self.client.xlimits = (3, None)
        assert self.client.xlimits == (3, 5)

    def test_xlimit_reverse_set(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])

        self.client.xlimits = 5, 3
        assert self.client.xlimits == (3, 5)

    def test_xlog_axes_labels(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])

        self.client.xlog = True
        assert self.client.axes.get_xlabel() == 'Log x'

        self.client.xlog = False
        assert self.client.axes.get_xlabel() == 'x'

        self.client.ylog = True
        assert self.client.axes.get_ylabel() == 'N'

        self.client.ylog = False
        assert self.client.axes.get_ylabel() == 'N'

    def test_xlog_snaps_limits(self):

        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])

        self.client.axes.set_xlim((-1, 1))
        self.client.xlog = True
        assert self.client.axes.get_xlim() != (-1, 1)

    def test_artist_clear_resets_arrays(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.components[0])
        for a in self.client._artists[self.data]:
            assert a.get_data()[0].size > 0
            a.clear()
            assert a.get_data()[0].size == 0

    def test_component_replaced(self):
        # regression test for 508
        self.client.register_to_hub(self.collect.hub)
        self.client.add_layer(self.data)
        self.client.component = self.data.components[0]

        test = ComponentID('test')
        self.data.update_id(self.client.component, test)
        assert self.client.component is test
Example #36
0
 def test_data_application(self):
     dc = DataCollection([Data(label='test', x=[1, 2, 3], y=[2, 3, 4])])
     app = GlueApplication(dc)
     self.check_clone(app)
Example #37
0
class TestCategoricalHistogram(TestHistogramClient):
    def setup_method(self, method):
        self.data = Data(y=[-1, -1, -1, -2, -2, -2, -3, -5, -7])
        self.data.add_component(
            CategoricalComponent(['a', 'a', 'a', 'b', 'c', 'd', 'd', 'e',
                                  'f']), 'x')
        self.subset = self.data.new_subset()
        self.collect = DataCollection(self.data)
        self.client = HistogramClient(self.collect, FIGURE)
        self.axes = self.client.axes
        FIGURE.canvas.draw = MagicMock()
        assert FIGURE.canvas.draw.call_count == 0

    def test_xlimit_single_set(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])

        self.client.xlimits = (None, 5)
        assert self.client.xlimits == (-0.5, 5)
        self.client.xlimits = (3, None)
        assert self.client.xlimits == (3, 5)

    def test_default_xlimits(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        assert self.client.xlimits == (-0.5, 5.5)
        self.client.set_component(self.data.id['y'])
        assert self.client.xlimits == (-7, -1)

    def test_change_default_bins(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        assert self.client.nbins == 6

    def test_tick_labels(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        correct_labels = ['a', 'b', 'c', 'd', 'e', 'f']
        formatter = self.client.axes.xaxis.get_major_formatter()
        xlabels = [formatter.format_data(pos) for pos in range(6)]
        assert correct_labels == xlabels

    def test_apply_roi(self):
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        # bins are 1...4

        self.data.edit_subset = [self.data.subsets[0]]

        roi = MagicMock()
        roi.to_polygon.return_value = [1.2, 2, 4], [2, 3, 4]

        self.client.apply_roi(roi)
        state = self.data.subsets[0].subset_state
        assert isinstance(state, CategoricalROISubsetState)
        np.testing.assert_equal(
            self.data.subsets[0].subset_state.roi.categories,
            np.array(['b', 'c', 'd', 'e']))

    # REMOVED TESTS
    def test_xlog_axes_labels(self):
        """ log-scale doesn't make sense for categorical data"""
        pass

    def test_xlog_snaps_limits(self):
        """ log-scale doesn't make sense for categorical data"""
        pass

    def test_apply_roi_xlog(self):
        """ log-scale doesn't make sense for categorical data"""
        pass

    def test_nbin_override_persists_over_attribute_change(self):
        # regression test for #398
        self.collect.append(self.data)
        self.client.add_layer(self.data)
        self.client.set_component(self.data.id['x'])
        self.client.nbins = 7
        self.client.set_component(self.data.id['y'])
        assert self.client.nbins == 7
Example #38
0
        raise NotImplementedError()
        self.ui.layerTree[key] = value

    def __contains__(self, obj):
        return obj in self.ui.layerTree

    def __len__(self):
        return len(self.ui.layerTree)


def save_subset(subset):
    assert isinstance(subset, core.subset.Subset)
    fname, fltr = QtGui.QFileDialog.getSaveFileName(
        caption="Select an output name",
        filter='FITS mask (*.fits);; Fits mask (*.fits)')
    fname = str(fname)
    if not fname:
        return
    subset.write_mask(fname)


if __name__ == "__main__":
    from glue.core.data_collection import DataCollection
    collection = DataCollection()
    from glue.external.qt import get_qapp
    app = get_qapp()
    widget = LayerTreeWidget()
    widget.setup(collection)
    widget.show()
    app.exec_()
Example #39
0
from glue.viewers.image.qt import ImageViewer

# create some data
data_path = Path("/home/stuart/sunpy/data/iris_glue/")
rasters = list(data_path.glob("*raster*"))
sji = list(data_path.glob("*SJI*"))

raster_data = _parse_iris_raster(read_iris_spectrograph_level2_fits(rasters),
                                 'iris')
sji_data = []

for s in sji:
    sji_data += load_data(s)

dc = DataCollection(raster_data + sji_data)
ga = GlueApplication(dc)

im1 = ga.new_data_viewer(ImageViewer)
im1.add_data(raster_data[0])

im2 = ga.new_data_viewer(ImageViewer)
im2.add_data(sji_data[0])


class IRISLinker:
    def __init__(self, im1, im2):
        self.im_raster = im1
        self.im_sji = im2

        self.im_raster.state.add_callback("slices", self._raster_update)
Example #40
0
def test_pixel_selection_subset_state():

    data1 = Data(x=np.ones((2, 4, 3)))
    data2 = Data(y=np.ones((4, 3, 2)))
    data3 = Data(z=np.ones((2, 3)))

    y_id = data2.main_components[0]
    z_id = data3.main_components[0]

    slice_1d = [slice(1, 2), slice(None), slice(None)]
    slice_2d = [slice(None), slice(2, 3), slice(1, 2)]
    slice_3d = [slice(1, 2), slice(2, 3), slice(1, 2)]

    state_1d = PixelSubsetState(data1, slice_1d)
    state_2d = PixelSubsetState(data1, slice_2d)
    state_3d = PixelSubsetState(data1, slice_3d)

    states = [state_1d, state_2d, state_3d]

    dc = DataCollection([data1, data2, data3])

    # Calling to_array with reference data should work by default, and not work
    # with unlinked datasets.

    for data in dc:
        for state in states:
            cid = data.main_components[0]
            if data is data1:
                assert_array_equal(state.to_array(data, cid),
                                   data[cid][state.slices])
            else:
                with pytest.raises(IncompatibleAttribute):
                    state.to_array(data, cid)

    # Add one set of links

    dc.add_link(
        LinkSame(data1.pixel_component_ids[0], data2.pixel_component_ids[2]))
    dc.add_link(
        LinkSame(data1.pixel_component_ids[0], data3.pixel_component_ids[0]))

    assert_array_equal(state_1d.to_array(data2, y_id), data2[y_id][:, :, 1:2])
    with pytest.raises(IncompatibleAttribute):
        state_2d.to_array(data2, y_id)
    with pytest.raises(IncompatibleAttribute):
        state_3d.to_array(data2, y_id)

    assert_array_equal(state_1d.to_array(data3, z_id), data3[z_id][1:2])
    with pytest.raises(IncompatibleAttribute):
        state_2d.to_array(data3, z_id)
    with pytest.raises(IncompatibleAttribute):
        state_3d.to_array(data3, z_id)

    # Add links with multiple components, in this case linking two cids with two cids

    def forwards(x, y):
        return x + y, x - y

    def backwards(x, y):
        return 0.5 * (x + y), 0.5 * (x - y)

    dc.add_link(
        MultiLink(data1.pixel_component_ids[1:],
                  data2.pixel_component_ids[:2],
                  forwards=forwards,
                  backwards=backwards))

    assert_array_equal(state_1d.to_array(data2, y_id), data2[y_id][:, :, 1:2])
    assert_array_equal(state_2d.to_array(data2, y_id), data2[y_id][2:3,
                                                                   1:2, :])
    assert_array_equal(state_3d.to_array(data2, y_id), data2[y_id][2:3, 1:2,
                                                                   1:2])

    assert_array_equal(state_1d.to_array(data3, z_id), data3[z_id][1:2])
    with pytest.raises(IncompatibleAttribute):
        state_2d.to_array(data3, z_id)
    with pytest.raises(IncompatibleAttribute):
        state_3d.to_array(data3, z_id)
Example #41
0
class TestCommunication(object):
    def setup_method(self, method):
        self.data = Data(x=[1, 2, 3, 2, 2, 3, 1])
        figure = MagicMock()
        self.collect = DataCollection()
        self.client = HistogramClient(self.collect, figure)
        self.axes = self.client.axes
        self.hub = self.collect.hub
        self.connect()

    def draw_count(self):
        return self.axes.figure.canvas.draw.call_count

    def connect(self):
        self.client.register_to_hub(self.hub)
        self.collect.register_to_hub(self.hub)

    def test_ignore_data_add_message(self):
        self.collect.append(self.data)
        assert not (self.client.layer_present(self.data))

    def test_update_data_ignored_if_data_not_present(self):
        self.collect.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.collect.append(self.data)
        self.client.add_layer(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.collect.append(self.data)
        sub = self.data.new_subset()
        assert not (self.client.layer_present(sub))

    def test_add_subset_processed_if_data_present(self):
        self.collect.append(self.data)
        self.client.add_layer(self.data)
        sub = self.data.new_subset()
        assert (self.client.layer_present(sub))

    def test_update_subset_ignored_if_not_present(self):
        self.collect.append(self.data)
        self.client.add_layer(self.data)
        sub = self.data.new_subset()
        self.client.remove_layer(sub)
        ct0 = self.draw_count()
        sub.style.color = 'blue'
        assert self.draw_count() == ct0

    def test_update_subset_processed_if_present(self):
        self.collect.append(self.data)
        self.client.add_layer(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.collect.append(self.data)
        self.client.add_layer(self.data)
        self.collect.remove(self.data)
        assert not self.client.layer_present(self.data)

    def test_subset_remove_message(self):
        self.collect.append(self.data)
        self.client.add_layer(self.data)
        sub = self.data.new_subset()
        assert self.client.layer_present(sub)
        sub.delete()
        assert not self.client.layer_present(sub)
Example #42
0
class TestScatterClient(object):

    def setup_method(self, method):
        self.data = example_data.test_data()
        self.ids = [self.data[0].find_component_id('a'),
                    self.data[0].find_component_id('b'),
                    self.data[1].find_component_id('c'),
                    self.data[1].find_component_id('d')]
        self.roi_limits = (0.5, 0.5, 1.5, 1.5)
        self.roi_points = (np.array([1]), np.array([1]))
        self.collect = DataCollection()
        EditSubsetMode().data_collection = self.collect

        self.hub = self.collect.hub

        FIGURE.clf()
        axes = FIGURE.add_subplot(111)
        self.client = ScatterClient(self.collect, axes=axes)

        self.connect()

    def teardown_method(self, methdod):
        self.assert_properties_correct()
        self.assert_axes_ticks_correct()

    def assert_properties_correct(self):
        ax = self.client.axes
        cl = self.client
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()
        assert abs(cl.xmin - min(xlim)) < 1e-2
        assert abs(cl.xmax - max(xlim)) < 1e-2
        assert abs(cl.ymin - min(ylim)) < 1e-2
        assert abs(cl.ymax - max(ylim)) < 1e-2
        assert cl.xflip == (xlim[1] < xlim[0])
        assert cl.yflip == (ylim[1] < ylim[0])
        assert cl.xlog == (ax.get_xscale() == 'log')
        assert cl.ylog == (ax.get_yscale() == 'log')
        assert (self.client.xatt is None) or isinstance(
            self.client.xatt, ComponentID)
        assert (self.client.yatt is None) or isinstance(
            self.client.yatt, ComponentID)

    def check_ticks(self, axis, is_log, is_cat):
        locator = axis.get_major_locator()
        formatter = axis.get_major_formatter()
        if is_log:
            assert isinstance(locator, LogLocator)
            assert isinstance(formatter, LogFormatterMathtext)
        elif is_cat:
            assert isinstance(locator, MaxNLocator)
            assert isinstance(formatter, FuncFormatter)
        else:
            assert isinstance(locator, AutoLocator)
            assert isinstance(formatter, ScalarFormatter)

    def assert_axes_ticks_correct(self):
        ax = self.client.axes
        client = self.client
        if client.xatt is not None:
            self.check_ticks(ax.xaxis,
                             client.xlog,
                             client._check_categorical(client.xatt))
        if client.yatt is not None:
            self.check_ticks(ax.yaxis,
                             client.ylog,
                             client._check_categorical(client.yatt))

    def plot_data(self, layer):
        """ Return the data bounds for a given layer (data or subset)
        Output format: [xmin, xmax], [ymin, ymax]
        """
        client = self.client
        x, y = client.artists[layer][0].get_data()
        xmin = x.min()
        xmax = x.max()
        ymin = y.min()
        ymax = y.max()
        return [xmin, xmax], [ymin, ymax]

    def plot_limits(self):
        """ Return the plot limits
        Output format [xmin, xmax], [ymin, ymax]
        """
        ax = self.client.axes
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()
        return (min(xlim), max(xlim)), (min(ylim), max(ylim))

    def assert_layer_inside_limits(self, layer):
        """Assert that points of a layer are within plot limits """
        xydata = self.plot_data(layer)
        xylimits = self.plot_limits()
        assert xydata[0][0] >= xylimits[0][0]
        assert xydata[1][0] >= xylimits[1][0]
        assert xydata[0][1] <= xylimits[0][1]
        assert xydata[1][1] <= xylimits[1][1]

    def setup_2d_data(self):
        d = Data(x=[[1, 2], [3, 4]], y=[[2, 4], [6, 8]])
        self.collect.append(d)
        self.client.add_layer(d)
        self.client.xatt = d.id['x']
        self.client.yatt = d.id['y']
        return d

    def add_data(self, data=None):
        if data is None:
            data = self.data[0]
        data.edit_subset = data.new_subset()
        self.collect.append(data)
        self.client.add_data(data)
        return data

    def add_data_and_attributes(self):
        data = self.add_data()
        data.edit_subset = data.new_subset()
        self.client.xatt = self.ids[0]
        self.client.yatt = self.ids[1]
        return data

    def is_first_in_front(self, front, back):
        z1 = self.client.get_layer_order(front)
        z2 = self.client.get_layer_order(back)
        return z1 > z2

    def connect(self):
        self.client.register_to_hub(self.hub)
        self.collect.register_to_hub(self.hub)

    def layer_drawn(self, layer):
        return self.client.is_layer_present(layer) and \
            all(a.enabled and a.visible for a in self.client.artists[layer])

    def layer_data_correct(self, layer, x, y):
        xx, yy = self.client.artists[layer][0].get_data()
        if max(abs(xx - x)) > .01:
            return False
        if max(abs(yy - y)) > .01:
            return False
        return True

    def test_empty_on_creation(self):
        for d in self.data:
            assert not self.client.is_layer_present(d)

    def test_add_external_data_raises_exception(self):
        data = Data()
        with pytest.raises(TypeError) as exc:
            self.client.add_data(data)
        assert exc.value.args[0] == "Layer not in data collection"

    def test_valid_add(self):
        self.add_data()
        assert self.client.is_layer_present(self.data[0])

    def test_axis_labels_sync_with_setters(self):
        self.add_data()
        self.client.xatt = self.ids[1]
        assert self.client.axes.get_xlabel() == self.ids[1].label
        self.client.yatt = self.ids[0]
        assert self.client.axes.get_ylabel() == self.ids[0].label

    def test_setters_require_componentID(self):
        self.add_data()
        with pytest.raises(TypeError):
            self.client.xatt = self.ids[1]._label
        self.client.xatt = self.ids[1]

    def test_logs(self):
        self.add_data()
        self.client.xlog = True
        assert self.client.axes.get_xscale() == 'log'

        self.client.xlog = False
        assert self.client.axes.get_xscale() == 'linear'

        self.client.ylog = True
        assert self.client.axes.get_yscale() == 'log'

        self.client.ylog = False
        assert self.client.axes.get_yscale() == 'linear'

    def test_flips(self):
        self.add_data()

        self.client.xflip = True
        self.assert_flips(True, False)

        self.client.xflip = False
        self.assert_flips(False, False)

        self.client.yflip = True
        self.assert_flips(False, True)

        self.client.yflip = False
        self.assert_flips(False, False)

    def assert_flips(self, xflip, yflip):
        ax = self.client.axes
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()
        assert (xlim[1] < xlim[0]) == xflip
        assert (ylim[1] < ylim[0]) == yflip

    def test_double_add(self):
        n0 = len(self.client.axes.lines)
        layer = self.add_data_and_attributes()
        # data present
        assert len(self.client.axes.lines) == n0 + 1 + len(layer.subsets)
        layer = self.add_data()
        # data still present
        assert len(self.client.axes.lines) == n0 + 1 + len(layer.subsets)

    def test_data_updates_propagate(self):
        layer = self.add_data_and_attributes()
        assert self.layer_drawn(layer)
        self.client._layer_updated = False
        layer.style.color = 'k'
        assert self.client._layer_updated

    def test_data_removal(self):
        layer = self.add_data()
        subset = layer.new_subset()
        self.collect.remove(layer)
        assert not self.client.is_layer_present(layer)
        assert not self.client.is_layer_present(subset)

    def test_add_subset_while_connected(self):
        layer = self.add_data()
        subset = layer.new_subset()
        assert self.client.is_layer_present(subset)

    def test_subset_removal(self):
        layer = self.add_data()
        subset = layer.new_subset()
        assert self.client.is_layer_present(layer)
        subset.delete()
        assert not self.client.is_layer_present(subset)

    def test_subset_removal_removes_from_plot(self):
        layer = self.add_data_and_attributes()
        subset = layer.new_subset()
        ct0 = len(self.client.axes.lines)
        subset.delete()
        assert len(self.client.axes.lines) == ct0 - 1

    def test_add_subset_to_untracked_data(self):
        subset = self.data[0].new_subset()
        assert not self.client.is_layer_present(subset)

    def test_valid_plot_data(self):
        layer = self.add_data_and_attributes()
        x = layer[self.ids[0]]
        y = layer[self.ids[1]]
        assert self.layer_data_correct(layer, x, y)

    def test_attribute_update_plot_data(self):
        layer = self.add_data_and_attributes()
        x = layer[self.ids[0]]
        y = layer[self.ids[0]]
        self.client.yatt = self.ids[0]
        assert self.layer_data_correct(layer, x, y)

    def test_invalid_plot(self):
        layer = self.add_data_and_attributes()
        assert self.layer_drawn(layer)
        c = ComponentID('bad id')
        self.client.xatt = c
        assert not self.layer_drawn(layer)
        self.client.xatt = self.ids[0]

    def test_redraw_called_on_invalid_plot(self):
        """ Plot should be updated when given invalid data,
        to sync layers' disabled/invisible states"""
        ctr = MagicMock()
        layer = self.add_data_and_attributes()
        assert self.layer_drawn(layer)
        c = ComponentID('bad id')
        self.client._redraw = ctr
        ct0 = ctr.call_count
        self.client.xatt = c
        ct1 = ctr.call_count
        ncall = ct1 - ct0
        expected = len(self.client.artists)
        assert ncall >= expected
        self.client.xatt = self.ids[0]

    def test_two_incompatible_data(self):
        d0 = self.add_data(self.data[0])
        d1 = self.add_data(self.data[1])
        self.client.xatt = self.ids[0]
        self.client.yatt = self.ids[1]
        x = d0[self.ids[0]]
        y = d0[self.ids[1]]
        assert self.layer_drawn(d0)
        assert self.layer_data_correct(d0, x, y)
        assert not self.layer_drawn(d1)

        self.client.xatt = self.ids[2]
        self.client.yatt = self.ids[3]
        x = d1[self.ids[2]]
        y = d1[self.ids[3]]
        assert self.layer_drawn(d1)
        assert self.layer_data_correct(d1, x, y)
        assert not self.layer_drawn(d0)

    def test_subsets_connect_with_data(self):
        data = self.data[0]
        s1 = data.new_subset()
        s2 = data.new_subset()
        self.collect.append(data)
        self.client.add_data(data)
        assert self.client.is_layer_present(s1)
        assert self.client.is_layer_present(s2)
        assert self.client.is_layer_present(data)

        # should also work with add_layer
        self.collect.remove(data)
        assert data not in self.collect
        assert not self.client.is_layer_present(s1)
        self.collect.append(data)
        self.client.add_layer(data)
        assert self.client.is_layer_present(s1)

    def test_edit_subset_connect_with_data(self):
        data = self.add_data()
        assert self.client.is_layer_present(data.edit_subset)

    def test_edit_subset_removed_with_data(self):
        data = self.add_data()
        self.collect.remove(data)
        assert not self.client.is_layer_present(data.edit_subset)

    def test_apply_roi(self):
        data = self.add_data_and_attributes()
        roi = RectangularROI()
        roi.update_limits(*self.roi_limits)
        x, y = self.roi_points
        self.client.apply_roi(roi)
        assert self.layer_data_correct(data.edit_subset, x, y)

    def test_apply_roi_adds_on_empty(self):
        data = self.add_data_and_attributes()
        data._subsets = []
        data.edit_subset = None
        roi = RectangularROI()
        roi.update_limits(*self.roi_limits)
        x, y = self.roi_points
        self.client.apply_roi(roi)
        assert data.edit_subset is not None

    def test_apply_roi_applies_to_all_editable_subsets(self):
        d1 = self.add_data_and_attributes()
        d2 = self.add_data()
        state1 = d1.edit_subset.subset_state
        state2 = d2.edit_subset.subset_state
        roi = RectangularROI()
        roi.update_limits(*self.roi_limits)
        x, y = self.roi_points
        self.client.apply_roi(roi)
        assert d1.edit_subset.subset_state is not state1
        assert d1.edit_subset.subset_state is not state2

    def test_apply_roi_doesnt_add_if_any_selection(self):
        d1 = self.add_data_and_attributes()
        d2 = self.add_data()
        d1.edit_subset = None
        d2.edit_subset = d2.new_subset()
        ct = len(d1.subsets)
        roi = RectangularROI()
        roi.update_limits(*self.roi_limits)
        x, y = self.roi_points
        self.client.apply_roi(roi)
        assert len(d1.subsets) == ct

    def test_subsets_drawn_over_data(self):
        data = self.add_data_and_attributes()
        subset = data.new_subset()
        assert self.is_first_in_front(subset, data)

    def test_log_sticky(self):
        self.add_data_and_attributes()
        self.assert_logs(False, False)

        self.client.xlog = True
        self.client.ylog = True
        self.assert_logs(True, True)

        self.client.xatt = self.ids[1]
        self.client.yatt = self.ids[0]
        self.assert_logs(True, True)

    def test_log_ticks(self):
        # regression test for 354
        self.add_data_and_attributes()
        self.assert_logs(False, False)

        self.client.xlog = True

        self.client.yatt = self.ids[0]

        self.assert_logs(True, False)
        assert not isinstance(self.client.axes.yaxis.get_major_locator(),
                              LogLocator)

    def assert_logs(self, xlog, ylog):
        ax = self.client.axes
        assert ax.get_xscale() == ('log' if xlog else 'linear')
        assert ax.get_yscale() == ('log' if ylog else 'linear')

    def test_flip_sticky(self):
        self.add_data_and_attributes()
        self.client.xflip = True
        self.assert_flips(True, False)
        self.client.xatt = self.ids[1]
        self.assert_flips(True, False)
        self.client.xatt = self.ids[0]
        self.assert_flips(True, False)

    def test_visibility_sticky(self):
        data = self.add_data_and_attributes()
        roi = RectangularROI()
        roi.update_limits(*self.roi_limits)
        assert self.client.is_visible(data.edit_subset)
        self.client.apply_roi(roi)
        self.client.set_visible(data.edit_subset, False)
        assert not self.client.is_visible(data.edit_subset)
        self.client.apply_roi(roi)
        assert not self.client.is_visible(data.edit_subset)

    def test_2d_data(self):
        """Should be abple to plot 2d data"""
        data = self.setup_2d_data()
        assert self.layer_data_correct(data, [1, 2, 3, 4], [2, 4, 6, 8])

    def test_2d_data_limits_with_subset(self):
        """visible limits should work with subsets and 2d data"""
        d = self.setup_2d_data()
        state = d.id['x'] > 2
        s = d.new_subset()
        s.subset_state = state
        assert self.client._visible_limits(0) == (1, 4)
        assert self.client._visible_limits(1) == (2, 8)

    def test_limits_nans(self):
        d = Data()
        x = Component(np.array([[1, 2], [np.nan, 4]]))
        y = Component(np.array([[2, 4], [np.nan, 8]]))
        xid = d.add_component(x, 'x')
        yid = d.add_component(y, 'y')
        self.collect.append(d)
        self.client.add_layer(d)
        self.client.xatt = xid
        self.client.yatt = yid

        assert self.client._visible_limits(0) == (1, 4)
        assert self.client._visible_limits(1) == (2, 8)

    def test_limits_inf(self):
        d = Data()
        x = Component(np.array([[1, 2], [np.infty, 4]]))
        y = Component(np.array([[2, 4], [-np.infty, 8]]))
        xid = d.add_component(x, 'x')
        yid = d.add_component(y, 'y')
        self.collect.append(d)
        self.client.add_layer(d)
        self.client.xatt = xid
        self.client.yatt = yid

        assert self.client._visible_limits(0) == (1, 4)
        assert self.client._visible_limits(1) == (2, 8)

    def test_xlog_relimits_if_negative(self):
        self.add_data_and_attributes()
        self.client.xflip = False
        self.client.xlog = False

        self.client.axes.set_xlim(-5, 5)
        self.client.xlog = True
        assert self.client.axes.get_xlim()[0] > .9

    def test_ylog_relimits_if_negative(self):
        self.add_data_and_attributes()
        self.client.yflip = False
        self.client.ylog = False
        self.client.axes.set_ylim(-5, 5)

        self.client.ylog = True
        assert self.client.axes.get_ylim()[0] > .9

    def test_subset_added_only_if_data_layer_present(self):
        self.collect.append(self.data[0])
        assert self.data[0] not in self.client.artists
        s = self.data[0].new_subset()
        assert s not in self.client.artists

    def test_pull_properties(self):
        ax = self.client.axes
        ax.set_xlim(6, 5)
        ax.set_ylim(8, 7)
        ax.set_xscale('log')
        ax.set_yscale('log')

        self.client._pull_properties()
        self.assert_properties_correct()

    def test_rescaled_on_init(self):
        layer = self.setup_2d_data()
        self.assert_layer_inside_limits(layer)

    def test_set_limits(self):
        self.client.xmin = 3
        self.client.xmax = 4
        self.client.ymin = 5
        self.client.ymax = 6
        ax = self.client.axes
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()

        assert xlim[0] == self.client.xmin
        assert xlim[1] == self.client.xmax
        assert ylim[0] == self.client.ymin
        assert ylim[1] == self.client.ymax

    def test_ignore_duplicate_updates(self):
        """Need not create new artist on every draw. Enforce this"""
        layer = self.setup_2d_data()

        m = MagicMock()
        self.client.artists[layer][0].clear = m

        self.client._update_layer(layer)
        ct0 = m.call_count

        self.client._update_layer(layer)
        ct1 = m.call_count

        assert ct1 == ct0

    def test_range_rois_preserved(self):
        data = self.add_data_and_attributes()
        assert self.client.xatt is not self.client.yatt

        roi = XRangeROI()
        roi.set_range(1, 2)
        self.client.apply_roi(roi)
        assert isinstance(data.edit_subset.subset_state,
                          RangeSubsetState)
        assert data.edit_subset.subset_state.att == self.client.xatt

        roi = RectangularROI()
        roi = YRangeROI()
        roi.set_range(1, 2)
        self.client.apply_roi(roi)
        assert data.edit_subset.subset_state.att == self.client.yatt

    def test_component_replaced(self):
        # regression test for #508
        data = self.add_data_and_attributes()
        test = ComponentID('test')
        data.update_id(self.client.xatt, test)
        assert self.client.xatt is test