import numpy as np

from numpy.testing import assert_allclose

from echo import CallbackProperty, ListCallbackProperty
from glue.core import Data, DataCollection

from .test_state import clone
from ..state_objects import (State, StateAttributeLimitsHelper,
                             StateAttributeSingleValueHelper,
                             StateAttributeHistogramHelper)


class SimpleTestState(State):
    a = CallbackProperty()
    b = CallbackProperty()
    flat = ListCallbackProperty()
    nested = ListCallbackProperty()


def test_state_serialization():

    state1 = SimpleTestState()
    state1.a = 2
    state1.b = 'hello'
    state1.flat = [1, 3, 4]

    sub_state = SimpleTestState()
    sub_state.a = 3
    sub_state.b = 'blah'
    sub_state.flat = [1, 2]
    sub_state.nested = []

    state1.nested = [1, 3, sub_state]

    state2 = clone(state1)

    assert state2.a == 2
    assert state2.b == 'hello'
    assert state2.flat == [1, 3, 4]
    assert state2.nested[0:2] == [1, 3]
    assert state2.nested[2].a == 3
    assert state2.nested[2].b == 'blah'
    assert state2.nested[2].flat == [1, 2]
    assert state2.nested[2].nested == []


EXPECTED_STR = """
a: 2
b: hello
flat: <CallbackList with 3 elements>
nested: <CallbackList with 3 elements>
"""

EXPECTED_REPR = """
<SimpleTestState
  a: 2
  b: hello
  flat: <CallbackList with 3 elements>
  nested: <CallbackList with 3 elements>
>
"""


def test_state_str_repr():

    state1 = SimpleTestState()
    state1.a = 2
    state1.b = 'hello'
    state1.flat = [1, 3, 4]

    sub_state = SimpleTestState()

    state1.nested = [1, 3, sub_state]

    assert str(state1) == EXPECTED_STR.strip()
    assert repr(state1) == EXPECTED_REPR.strip()


class TestStateAttributeLimitsHelper():

    def setup_method(self, method):

        self.data = Data(x=np.linspace(-100, 100, 10000),
                         y=np.linspace(2, 3, 10000), label='test_data')

        self.data_collection = DataCollection([self.data])

        class SimpleState(State):

            layer = CallbackProperty()
            comp = CallbackProperty()
            lower = CallbackProperty()
            upper = CallbackProperty()
            log = CallbackProperty(False)
            scale = CallbackProperty(100)

        self.state = SimpleState()

        self.helper = StateAttributeLimitsHelper(self.state, attribute='comp',
                                                 lower='lower', upper='upper',
                                                 percentile='scale', log='log')
        self.state.data = self.data
        self.state.comp = self.data.id['x']

        self.x_id = self.data.main_components[0]
        self.y_id = self.data.main_components[1]

    def test_minmax(self):
        assert self.helper.lower == -100
        assert self.helper.upper == +100

    def test_change_attribute(self):
        self.helper.attribute = self.y_id
        assert self.helper.lower == 2
        assert self.helper.upper == 3
        self.helper.attribute = self.x_id
        assert self.helper.lower == -100
        assert self.helper.upper == +100

    def test_change_percentile(self):

        # Changing scale mode updates the limits
        self.helper.percentile = 99.5
        assert_allclose(self.helper.lower, -99.5)
        assert_allclose(self.helper.upper, +99.5)
        self.helper.percentile = 99
        assert_allclose(self.helper.lower, -99)
        assert_allclose(self.helper.upper, +99)
        self.helper.percentile = 90
        assert_allclose(self.helper.lower, -90)
        assert_allclose(self.helper.upper, +90)

        # When switching to custom, the last limits are retained
        self.helper.percentile = "Custom"
        assert_allclose(self.helper.lower, -90)
        assert_allclose(self.helper.upper, +90)

    def test_percentile_cached(self):
        # Make sure that if we change scale and change attribute, the scale
        # modes are cached on a per-attribute basis.
        self.helper.percentile = 99.5
        self.state.comp = self.y_id
        assert self.helper.percentile == 100
        self.helper.percentile = 99
        self.state.comp = self.x_id
        assert self.helper.percentile == 99.5
        self.state.comp = self.y_id
        assert self.helper.percentile == 99

    def test_flip_button(self):

        self.helper.flip_limits()

        assert self.helper.lower == +100
        assert self.helper.upper == -100

        # Make sure that values were re-cached when flipping
        self.state.comp = self.y_id
        assert self.helper.lower == 2
        assert self.helper.upper == 3
        self.state.comp = self.x_id
        assert self.helper.lower == +100
        assert self.helper.upper == -100

    def test_manual_edit(self):

        # Make sure that values are re-cached when edited manually
        self.helper.percentile = "Custom"
        self.state.lower = -122
        self.state.upper = 234
        self.helper.log = True
        assert self.helper.lower == -122
        assert self.helper.upper == 234
        assert self.helper.log
        self.state.comp = self.y_id
        assert self.helper.lower == 2
        assert self.helper.upper == 3
        assert not self.helper.log
        self.state.comp = self.x_id
        assert self.helper.lower == -122
        assert self.helper.upper == 234
        assert self.helper.log


class TestStateAttributeSingleValueHelper():

    def setup_method(self, method):

        self.data = Data(x=np.linspace(-100, 30, 9999),
                         y=np.linspace(2, 3, 9999), label='test_data')

        self.data_collection = DataCollection([self.data])

        class SimpleState(State):

            layer = CallbackProperty()
            comp = CallbackProperty()
            val = CallbackProperty()

        self.state = SimpleState()

        self.helper = StateAttributeSingleValueHelper(self.state, attribute='comp',
                                                      function=np.nanmedian, value='val')

        self.state.data = self.data

        self.state.comp = self.data.id['x']

        self.x_id = self.data.main_components[0]
        self.y_id = self.data.main_components[1]

    def test_value(self):
        assert self.helper.value == -35.

    def test_change_attribute(self):
        self.helper.attribute = self.y_id
        assert self.helper.value == 2.5
        self.helper.attribute = self.x_id
        assert self.helper.value == -35

    def test_manual_edit(self):
        self.state.val = 42.
        assert self.helper.value == 42
        self.state.comp = self.y_id
        assert self.helper.value == 2.5
        self.state.comp = self.x_id
        assert self.helper.value == 42


class TestStateAttributeHistogramHelper():

    def setup_method(self, method):

        self.data = Data(x=[-3.2, 4.3, 2.2, 5.4, 7.2, -1.1, 2.3],
                         y=['a', 'f', 'd', 'e', 'f', 'f', 'a'], label='test_data')

        self.data_collection = DataCollection([self.data])

        class SimpleState(State):

            layer = CallbackProperty()
            comp = CallbackProperty()
            x_min = CallbackProperty()
            x_max = CallbackProperty()
            n_bin = CallbackProperty()

        self.state = SimpleState()

        self.helper = StateAttributeHistogramHelper(self.state, attribute='comp',
                                                    lower='x_min', upper='x_max', n_bin='n_bin')

        self.state.data = self.data

    def test_default_numerical(self):
        self.state.comp = self.data.id['x']
        assert self.state.x_min == -3.2
        assert self.state.x_max == 7.2
        assert self.state.n_bin == 15

    def test_default_categorical(self):
        self.state.comp = self.data.id['y']
        assert self.state.x_min == -0.5
        assert self.state.x_max == 3.5
        assert self.state.n_bin == 4

    def test_hitting_limits(self):

        # FIXME: here we modify the internal defaults rather than making a new
        # state helper, but this could be improved
        self.helper._default_n_bin = 4
        self.helper._max_n_bin = 3

        self.state.comp = self.data.id['x']
        assert self.state.x_min == -3.2
        assert self.state.x_max == 7.2
        assert self.state.n_bin == 4

        self.state.comp = self.data.id['y']
        assert self.state.x_min == -0.5
        assert self.state.x_max == 3.5
        assert self.state.n_bin == 3

    def test_caching(self):
        self.state.comp = self.data.id['x']
        self.state.x_min = 2
        self.state.x_max = 7
        self.state.n_bin = 8
        self.state.comp = self.data.id['y']
        self.state.x_min = 1.5
        self.state.x_max = 3.5
        self.state.n_bin = 3
        self.state.comp = self.data.id['x']
        assert self.state.x_min == 2
        assert self.state.x_max == 7
        assert self.state.n_bin == 8
        self.state.comp = self.data.id['y']
        assert self.state.x_min == 1.5
        assert self.state.x_max == 3.5
        assert self.state.n_bin == 3


def test_histogram_helper_common_n_bin():

    data = Data(x=[-3.2, 4.3, 2.2],
                y=['a', 'f', 'd'],
                z=[1.1, 2.3, 1.2],
                label='test_data')

    class SimpleState(State):

        layer = CallbackProperty()
        comp = CallbackProperty()
        x_min = CallbackProperty()
        x_max = CallbackProperty()
        n_bin = CallbackProperty()
        common = CallbackProperty()

    state = SimpleState()

    helper = StateAttributeHistogramHelper(state, attribute='comp',
                                           lower='x_min', upper='x_max', n_bin='n_bin',
                                           common_n_bin='common')

    state.data = data

    state.comp = data.id['x']
    state.n_bin = 9
    state.comp = data.id['y']
    assert state.n_bin == 3
    state.comp = data.id['z']
    assert state.n_bin == 15

    state.n_bin = 12

    state.common = True

    state.comp = data.id['x']
    assert state.n_bin == 12

    state.n_bin = 11

    state.comp = data.id['y']
    assert state.n_bin == 3
    state.comp = data.id['z']
    assert state.n_bin == 11

    state.common = False
    state.n_bin = 13

    state.comp = data.id['x']
    assert state.n_bin == 11


def test_histogram_helper_common_n_bin_active():

    # Make sure that common_n_bin works as expected if True from start

    data = Data(x=[-3.2, 4.3, 2.2],
                y=['a', 'f', 'd'],
                z=[1.1, 2.3, 1.2],
                label='test_data')

    class SimpleState(State):

        layer = CallbackProperty()
        comp = CallbackProperty()
        x_min = CallbackProperty()
        x_max = CallbackProperty()
        n_bin = CallbackProperty()
        common = CallbackProperty(True)

    state = SimpleState()

    helper = StateAttributeHistogramHelper(state, attribute='comp',
                                           lower='x_min', upper='x_max', n_bin='n_bin',
                                           common_n_bin='common')

    state.data = data

    state.comp = data.id['x']
    state.n_bin = 9
    state.comp = data.id['z']
    assert state.n_bin == 9

    state.n_bin = 12

    state.common = True

    state.comp = data.id['x']
    assert state.n_bin == 12

    state.n_bin = 11

    state.comp = data.id['y']
    assert state.n_bin == 3
    state.comp = data.id['z']
    assert state.n_bin == 11

    state.common = False
    state.n_bin = 13

    state.comp = data.id['x']
    assert state.n_bin == 11


def test_limits_helper_initial_values():

    # Regression test for a bug that occurred if the limits cache was empty
    # but some attributes were set to values - in this case we don't want to
    # override the existing values.

    data = Data(x=np.linspace(-100, 100, 10000),
                y=np.linspace(2, 3, 10000), label='test_data')

    class SimpleState(State):

        layer = CallbackProperty()
        comp = CallbackProperty()
        lower = CallbackProperty()
        upper = CallbackProperty()

    state = SimpleState()
    state.lower = 1
    state.upper = 2
    state.comp = data.id['x']

    helper = StateAttributeLimitsHelper(state, attribute='comp',
                                        lower='lower', upper='upper')

    assert helper.lower == 1
    assert helper.upper == 2


class DatetimeState(State):
    a = CallbackProperty()


def test_state_serialization_datetime64():

    state1 = DatetimeState()
    state1.a = np.datetime64(100, 'D')

    state2 = clone(state1)

    assert state2.a == np.datetime64(100, 'D')


def test_nan_inf_minmax():

    data = Data(x=[3, 1, -2, np.inf, np.nan], label='test_data')

    class SimpleState(State):

        layer = CallbackProperty()
        comp = CallbackProperty()
        lower = CallbackProperty()
        upper = CallbackProperty()
        percentile = CallbackProperty()
        log = CallbackProperty()

    state = SimpleState()

    helper = StateAttributeLimitsHelper(state, attribute='comp',  # noqa
                                        lower='lower', upper='upper',
                                        percentile='percentile', log='log')

    state.data = data
    state.comp = data.id['x']

    assert state.lower == -2
    assert state.upper == +3

    state.log = True

    assert state.lower == +1
    assert state.upper == +3

    state.log = False
    state.percentile = 99

    assert_allclose(state.lower, -1.97)
    assert_allclose(state.upper, +2.98)


def test_percentile_no_log():

    # Regression test for a bug that caused a crash if the state class had a
    # percentile attribute but no log.

    data = Data(x=np.linspace(-100, 100, 10000),
                y=np.linspace(2, 3, 10000), label='test_data')

    class SimpleState(State):

        layer = CallbackProperty()
        comp = CallbackProperty()
        lower = CallbackProperty()
        upper = CallbackProperty()
        scale = CallbackProperty()

    state = SimpleState()

    state.comp = data.id['x']
    state.lower = 2
    state.upper = 4

    helper = StateAttributeLimitsHelper(state, attribute='comp',
                                        lower='lower', upper='upper',
                                        percentile='scale')

    state.scale = 90

[((419, 437), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (435, 437), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((446, 464), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (462, 464), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((476, 498), 'echo.ListCallbackProperty', 'ListCallbackProperty', ([], {}), '()\n', (496, 498), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((512, 534), 'echo.ListCallbackProperty', 'ListCallbackProperty', ([], {}), '()\n', (532, 534), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((9115, 9201), 'glue.core.Data', 'Data', ([], {'x': '[-3.2, 4.3, 2.2]', 'y': "['a', 'f', 'd']", 'z': '[1.1, 2.3, 1.2]', 'label': '"""test_data"""'}), "(x=[-3.2, 4.3, 2.2], y=['a', 'f', 'd'], z=[1.1, 2.3, 1.2], label=\n    'test_data')\n", (9119, 9201), False, 'from glue.core import Data, DataCollection\n'), ((10417, 10503), 'glue.core.Data', 'Data', ([], {'x': '[-3.2, 4.3, 2.2]', 'y': "['a', 'f', 'd']", 'z': '[1.1, 2.3, 1.2]', 'label': '"""test_data"""'}), "(x=[-3.2, 4.3, 2.2], y=['a', 'f', 'd'], z=[1.1, 2.3, 1.2], label=\n    'test_data')\n", (10421, 10503), False, 'from glue.core import Data, DataCollection\n'), ((12376, 12394), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (12392, 12394), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((12485, 12508), 'numpy.datetime64', 'np.datetime64', (['(100)', '"""D"""'], {}), "(100, 'D')\n", (12498, 12508), True, 'import numpy as np\n'), ((12626, 12679), 'glue.core.Data', 'Data', ([], {'x': '[3, 1, -2, np.inf, np.nan]', 'label': '"""test_data"""'}), "(x=[3, 1, -2, np.inf, np.nan], label='test_data')\n", (12630, 12679), False, 'from glue.core import Data, DataCollection\n'), ((13418, 13453), 'numpy.testing.assert_allclose', 'assert_allclose', (['state.lower', '(-1.97)'], {}), '(state.lower, -1.97)\n', (13433, 13453), False, 'from numpy.testing import assert_allclose\n'), ((13458, 13493), 'numpy.testing.assert_allclose', 'assert_allclose', (['state.upper', '(+2.98)'], {}), '(state.upper, +2.98)\n', (13473, 13493), False, 'from numpy.testing import assert_allclose\n'), ((1961, 1988), 'glue.core.DataCollection', 'DataCollection', (['[self.data]'], {}), '([self.data])\n', (1975, 1988), False, 'from glue.core import Data, DataCollection\n'), ((3243, 3284), 'numpy.testing.assert_allclose', 'assert_allclose', (['self.helper.lower', '(-99.5)'], {}), '(self.helper.lower, -99.5)\n', (3258, 3284), False, 'from numpy.testing import assert_allclose\n'), ((3293, 3334), 'numpy.testing.assert_allclose', 'assert_allclose', (['self.helper.upper', '(+99.5)'], {}), '(self.helper.upper, +99.5)\n', (3308, 3334), False, 'from numpy.testing import assert_allclose\n'), ((3379, 3418), 'numpy.testing.assert_allclose', 'assert_allclose', (['self.helper.lower', '(-99)'], {}), '(self.helper.lower, -99)\n', (3394, 3418), False, 'from numpy.testing import assert_allclose\n'), ((3427, 3466), 'numpy.testing.assert_allclose', 'assert_allclose', (['self.helper.upper', '(+99)'], {}), '(self.helper.upper, +99)\n', (3442, 3466), False, 'from numpy.testing import assert_allclose\n'), ((3511, 3550), 'numpy.testing.assert_allclose', 'assert_allclose', (['self.helper.lower', '(-90)'], {}), '(self.helper.lower, -90)\n', (3526, 3550), False, 'from numpy.testing import assert_allclose\n'), ((3559, 3598), 'numpy.testing.assert_allclose', 'assert_allclose', (['self.helper.upper', '(+90)'], {}), '(self.helper.upper, +90)\n', (3574, 3598), False, 'from numpy.testing import assert_allclose\n'), ((3715, 3754), 'numpy.testing.assert_allclose', 'assert_allclose', (['self.helper.lower', '(-90)'], {}), '(self.helper.lower, -90)\n', (3730, 3754), False, 'from numpy.testing import assert_allclose\n'), ((3763, 3802), 'numpy.testing.assert_allclose', 'assert_allclose', (['self.helper.upper', '(+90)'], {}), '(self.helper.upper, +90)\n', (3778, 3802), False, 'from numpy.testing import assert_allclose\n'), ((5619, 5646), 'glue.core.DataCollection', 'DataCollection', (['[self.data]'], {}), '([self.data])\n', (5633, 5646), False, 'from glue.core import Data, DataCollection\n'), ((6814, 6921), 'glue.core.Data', 'Data', ([], {'x': '[-3.2, 4.3, 2.2, 5.4, 7.2, -1.1, 2.3]', 'y': "['a', 'f', 'd', 'e', 'f', 'f', 'a']", 'label': '"""test_data"""'}), "(x=[-3.2, 4.3, 2.2, 5.4, 7.2, -1.1, 2.3], y=['a', 'f', 'd', 'e', 'f',\n    'f', 'a'], label='test_data')\n", (6818, 6921), False, 'from glue.core import Data, DataCollection\n'), ((6975, 7002), 'glue.core.DataCollection', 'DataCollection', (['[self.data]'], {}), '([self.data])\n', (6989, 7002), False, 'from glue.core import Data, DataCollection\n'), ((9293, 9311), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (9309, 9311), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((9327, 9345), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (9343, 9345), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((9362, 9380), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (9378, 9380), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((9397, 9415), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (9413, 9415), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((9432, 9450), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (9448, 9450), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((9468, 9486), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (9484, 9486), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((10595, 10613), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (10611, 10613), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((10629, 10647), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (10645, 10647), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((10664, 10682), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (10680, 10682), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((10699, 10717), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (10715, 10717), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((10734, 10752), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (10750, 10752), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((10770, 10792), 'echo.CallbackProperty', 'CallbackProperty', (['(True)'], {}), '(True)\n', (10786, 10792), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((11923, 11941), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (11939, 11941), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((11957, 11975), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (11973, 11975), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((11992, 12010), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (12008, 12010), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((12027, 12045), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (12043, 12045), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((12561, 12584), 'numpy.datetime64', 'np.datetime64', (['(100)', '"""D"""'], {}), "(100, 'D')\n", (12574, 12584), True, 'import numpy as np\n'), ((12728, 12746), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (12744, 12746), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((12762, 12780), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (12778, 12780), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((12797, 12815), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (12813, 12815), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((12832, 12850), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (12848, 12850), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((12872, 12890), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (12888, 12890), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((12905, 12923), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (12921, 12923), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((13804, 13822), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (13820, 13822), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((13838, 13856), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (13854, 13856), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((13873, 13891), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (13889, 13891), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((13908, 13926), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (13924, 13926), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((13943, 13961), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (13959, 13961), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((2045, 2063), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (2061, 2063), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((2083, 2101), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (2099, 2101), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((2122, 2140), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (2138, 2140), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((2161, 2179), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (2177, 2179), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((2198, 2221), 'echo.CallbackProperty', 'CallbackProperty', (['(False)'], {}), '(False)\n', (2214, 2221), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((2242, 2263), 'echo.CallbackProperty', 'CallbackProperty', (['(100)'], {}), '(100)\n', (2258, 2263), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((5703, 5721), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (5719, 5721), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((5741, 5759), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (5757, 5759), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((5778, 5796), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (5794, 5796), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((7059, 7077), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (7075, 7077), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((7097, 7115), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (7113, 7115), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((7136, 7154), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (7152, 7154), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((7175, 7193), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (7191, 7193), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((7214, 7232), 'echo.CallbackProperty', 'CallbackProperty', ([], {}), '()\n', (7230, 7232), False, 'from echo import CallbackProperty, ListCallbackProperty\n'), ((11781, 11810), 'numpy.linspace', 'np.linspace', (['(-100)', '(100)', '(10000)'], {}), '(-100, 100, 10000)\n', (11792, 11810), True, 'import numpy as np\n'), ((11830, 11854), 'numpy.linspace', 'np.linspace', (['(2)', '(3)', '(10000)'], {}), '(2, 3, 10000)\n', (11841, 11854), True, 'import numpy as np\n'), ((13662, 13691), 'numpy.linspace', 'np.linspace', (['(-100)', '(100)', '(10000)'], {}), '(-100, 100, 10000)\n', (13673, 13691), True, 'import numpy as np\n'), ((13711, 13735), 'numpy.linspace', 'np.linspace', (['(2)', '(3)', '(10000)'], {}), '(2, 3, 10000)\n', (13722, 13735), True, 'import numpy as np\n'), ((1826, 1855), 'numpy.linspace', 'np.linspace', (['(-100)', '(100)', '(10000)'], {}), '(-100, 100, 10000)\n', (1837, 1855), True, 'import numpy as np\n'), ((1884, 1908), 'numpy.linspace', 'np.linspace', (['(2)', '(3)', '(10000)'], {}), '(2, 3, 10000)\n', (1895, 1908), True, 'import numpy as np\n'), ((5487, 5514), 'numpy.linspace', 'np.linspace', (['(-100)', '(30)', '(9999)'], {}), '(-100, 30, 9999)\n', (5498, 5514), True, 'import numpy as np\n'), ((5543, 5566), 'numpy.linspace', 'np.linspace', (['(2)', '(3)', '(9999)'], {}), '(2, 3, 9999)\n', (5554, 5566), True, 'import numpy as np\n')]