Пример #1
0
    def test_label_base_from_transform(self, x):

        s = Continuous(trans="log")
        a = PseudoAxis(s._setup(x, Coordinate())._matplotlib_scale)
        a.set_view_interval(10, 1000)
        label, = a.major.formatter.format_ticks([100])
        assert r"10^{2}" in label
Пример #2
0
    def test_log_tick_count(self, x):

        with pytest.raises(RuntimeError, match="`count` requires"):
            Continuous(trans="log").tick(count=4)

        s = Continuous(trans="log").tick(count=4, between=(1, 1000))
        a = PseudoAxis(s._setup(x, Coordinate())._matplotlib_scale)
        a.set_view_interval(.5, 1050)
        assert_array_equal(a.major.locator(), [1, 10, 100, 1000])
Пример #3
0
    def test_tick_upto(self, x):

        for n in [2, 5, 10]:
            s = Continuous().tick(upto=n).setup(x, Coordinate())
            a = PseudoAxis(s.matplotlib_scale)
            a.set_view_interval(0, 1)
            assert len(a.major.locator()) <= (n + 1)
Пример #4
0
    def test_tick_count(self, x):

        n = 8
        s = Continuous().tick(count=n).setup(x, Coordinate())
        a = PseudoAxis(s.matplotlib_scale)
        a.set_view_interval(0, 1)
        assert_array_equal(a.major.locator(), np.linspace(0, 1, n))
Пример #5
0
    def setup_labels(self, x, *args, **kwargs):

        s = Continuous().label(*args, **kwargs)._setup(x, Coordinate())
        a = PseudoAxis(s._matplotlib_scale)
        a.set_view_interval(0, 1)
        locs = a.major.locator()
        return a, locs
Пример #6
0
    def test_tick_at(self, x):

        locs = [.2, .5, .9]
        s = Continuous().tick(at=locs).setup(x, Coordinate())
        a = PseudoAxis(s.matplotlib_scale)
        a.set_view_interval(0, 1)
        assert_array_equal(a.major.locator(), locs)
Пример #7
0
    def test_tick_every(self, x):

        for d in [.05, .2, .5]:
            s = Continuous().tick(every=d).setup(x, Coordinate())
            a = PseudoAxis(s.matplotlib_scale)
            a.set_view_interval(0, 1)
            assert np.allclose(np.diff(a.major.locator()), d)
Пример #8
0
    def test_log_tick_default(self, x):

        s = Continuous(trans="log")._setup(x, Coordinate())
        a = PseudoAxis(s._matplotlib_scale)
        a.set_view_interval(.5, 1050)
        ticks = a.major.locator()
        assert np.allclose(np.diff(np.log10(ticks)), 1)
Пример #9
0
    def test_tick_count_between(self, x):

        n = 5
        lo, hi = .2, .7
        s = Continuous().tick(count=n, between=(lo, hi)).setup(x, Coordinate())
        a = PseudoAxis(s.matplotlib_scale)
        a.set_view_interval(0, 1)
        assert_array_equal(a.major.locator(), np.linspace(lo, hi, n))
Пример #10
0
    def test_tick_locator(self, x):

        locs = [.2, .5, .8]
        locator = mpl.ticker.FixedLocator(locs)
        s = Continuous().tick(locator).setup(x, Coordinate())
        a = PseudoAxis(s.matplotlib_scale)
        a.set_view_interval(0, 1)
        assert_array_equal(a.major.locator(), locs)
Пример #11
0
    def test_tick_every_between(self, x):

        lo, hi = .2, .8
        for d in [.05, .2, .5]:
            s = Continuous().tick(every=d, between=(lo, hi)).setup(x, Coordinate())
            a = PseudoAxis(s.matplotlib_scale)
            a.set_view_interval(0, 1)
            expected = np.arange(lo, hi + d, d)
            assert_array_equal(a.major.locator(), expected)
Пример #12
0
    def test_tick_minor(self, x):

        n = 3
        s = Continuous().tick(count=2, minor=n).setup(x, Coordinate())
        a = PseudoAxis(s.matplotlib_scale)
        a.set_view_interval(0, 1)
        # I am not sure why matplotlib's minor ticks include the
        # largest major location but exclude the smalllest one ...
        expected = np.linspace(0, 1, n + 2)[1:]
        assert_array_equal(a.minor.locator(), expected)
Пример #13
0
    def test_symlog_tick_default(self, x):

        s = Continuous(trans="symlog")._setup(x, Coordinate())
        a = PseudoAxis(s._matplotlib_scale)
        a.set_view_interval(-1050, 1050)
        ticks = a.major.locator()
        assert ticks[0] == -ticks[-1]
        pos_ticks = np.sort(np.unique(np.abs(ticks)))
        assert np.allclose(np.diff(np.log10(pos_ticks[1:])), 1)
        assert pos_ticks[0] == 0
Пример #14
0
    def infer_scale(self, arg: Any, data: Series) -> Scale:
        # TODO when inferring Continuous without data, verify type

        # TODO need to rethink the variable type system
        # (e.g. boolean, ordered categories as Ordinal, etc)..
        var_type = variable_type(data, boolean_type="categorical")

        if isinstance(arg, (dict, list)):
            return Nominal(arg)

        if isinstance(arg, tuple):
            if var_type == "categorical":
                # TODO It seems reasonable to allow a gradient mapping for nominal
                # scale but it also feels "technically" wrong. Should this infer
                # Ordinal with categorical data and, if so, verify orderedness?
                return Nominal(arg)
            return Continuous(arg)

        if callable(arg):
            return Continuous(arg)

        # TODO Do we accept str like "log", "pow", etc. for semantics?

        # TODO what about
        # - Temporal? (i.e. datetime)
        # - Boolean?

        if not isinstance(arg, str):
            msg = " ".join([
                f"A single scale argument for {self.variable} variables must be",
                f"a string, dict, tuple, list, or callable, not {type(arg)}."
            ])
            raise TypeError(msg)

        if arg in QUAL_PALETTES:
            return Nominal(arg)
        elif var_type == "numeric":
            return Continuous(arg)
        # TODO implement scales for date variables and any others.
        else:
            return Nominal(arg)
Пример #15
0
    def test_label_type_checks(self):

        s = Continuous()
        with pytest.raises(TypeError, match="Label formatter must be"):
            s.label("{x}")

        with pytest.raises(TypeError, match="`like` must be"):
            s.label(like=2)
Пример #16
0
    def infer_scale(self, arg: Any, data: Series) -> Scale:
        """Given data and a scaling argument, initialize appropriate scale class."""

        # TODO infer continuous based on log/sqrt etc?

        if isinstance(arg, (list, dict)):
            return Nominal(arg)
        elif variable_type(data) == "categorical":
            return Nominal(arg)
        elif variable_type(data) == "datetime":
            return Temporal(arg)
        # TODO other variable types
        else:
            return Continuous(arg)
Пример #17
0
 def default_scale(self, data: Series) -> Scale:
     """Given data, initialize appropriate scale class."""
     # TODO allow variable_type to be "boolean" if that's a scale?
     # TODO how will this handle data with units that can be treated as numeric
     # if passed through a registered matplotlib converter?
     var_type = variable_type(data, boolean_type="numeric")
     if var_type == "numeric":
         return Continuous()
     elif var_type == "datetime":
         return Temporal()
     # TODO others
     # time-based (TimeStamp, TimeDelta, Period)
     # boolean scale?
     else:
         return Nominal()
Пример #18
0
 def infer_scale(self, arg: Any, data: Series) -> Scale:
     """Given data and a scaling argument, initialize appropriate scale class."""
     # TODO put these somewhere external for validation
     # TODO putting this here won't pick it up if subclasses define infer_scale
     # (e.g. color). How best to handle that? One option is to call super after
     # handling property-specific possibilities (e.g. for color check that the
     # arg is not a valid palette name) but that could get tricky.
     trans_args = ["log", "symlog", "logit", "pow", "sqrt"]
     if isinstance(arg, str):
         if any(arg.startswith(k) for k in trans_args):
             # TODO validate numeric type? That should happen centrally somewhere
             return Continuous(trans=arg)
         else:
             msg = f"Unknown magic arg for {self.variable} scale: '{arg}'."
             raise ValueError(msg)
     else:
         arg_type = type(arg).__name__
         msg = f"Magic arg for {self.variable} scale must be str, not {arg_type}."
         raise TypeError(msg)
Пример #19
0
    def test_interval_with_range_norm_and_transform(self, x):

        x = pd.Series([1, 10, 100])
        # TODO param order?
        s = Continuous((2, 3), (10, 100), "log")._setup(x, IntervalProperty())
        assert_array_equal(s(x), [1, 2, 3])
Пример #20
0
    def test_interval_with_norm(self, x):

        s = Continuous(norm=(3, 7))._setup(x, IntervalProperty())
        assert_array_equal(s(x), [-.5, 0, 1.5])
Пример #21
0
    def test_interval_with_range(self, x):

        s = Continuous((1, 3))._setup(x, IntervalProperty())
        assert_array_equal(s(x), [1, 1.5, 3])
Пример #22
0
    def test_interval_defaults(self, x):

        s = Continuous()._setup(x, IntervalProperty())
        assert_array_equal(s(x), [0, .25, 1])
Пример #23
0
    def test_coordinate_transform_error(self, x):

        s = Continuous(trans="bad")
        with pytest.raises(ValueError, match="Unknown value provided"):
            s._setup(x, Coordinate())
Пример #24
0
    def test_coordinate_transform_with_parameter(self, x):

        s = Continuous(trans="pow3")._setup(x, Coordinate())
        assert_series_equal(s(x), np.power(x, 3))
Пример #25
0
    def test_log_tick_every(self, x):

        with pytest.raises(RuntimeError, match="`every` not supported"):
            Continuous(trans="log").tick(every=2)
Пример #26
0
    def test_coordinate_defaults(self, x):

        s = Continuous()._setup(x, Coordinate())
        assert_series_equal(s(x), x)
Пример #27
0
    def setup_ticks(self, x, *args, **kwargs):

        s = Continuous().tick(*args, **kwargs)._setup(x, Coordinate())
        a = PseudoAxis(s._matplotlib_scale)
        a.set_view_interval(0, 1)
        return a
Пример #28
0
    def test_color_defaults(self, x):

        cmap = color_palette("ch:", as_cmap=True)
        s = Continuous()._setup(x, Color())
        assert_array_equal(s(x), cmap([0, .25, 1])[:, :3])  # FIXME RGBA
Пример #29
0
    def test_color_named_values(self, x):

        cmap = color_palette("viridis", as_cmap=True)
        s = Continuous("viridis")._setup(x, Color())
        assert_array_equal(s(x), cmap([0, .25, 1])[:, :3])  # FIXME RGBA
Пример #30
0
    def test_coordinate_transform(self, x):

        s = Continuous(trans="log")._setup(x, Coordinate())
        assert_series_equal(s(x), np.log10(x))