1#-----------------------------------------------------------------------------
2# Copyright (c) 2012 - 2021, Anaconda, Inc., and Bokeh Contributors.
3# All rights reserved.
4#
5# The full license is in the file LICENSE.txt, distributed with this software.
6#-----------------------------------------------------------------------------
7
8#-----------------------------------------------------------------------------
9# Boilerplate
10#-----------------------------------------------------------------------------
11import pytest ; pytest
12
13#-----------------------------------------------------------------------------
14# Imports
15#-----------------------------------------------------------------------------
16
17# Standard library imports
18import datetime
19
20# External imports
21import numpy as np
22
23# Bokeh imports
24from bokeh.models import (
25    CategoricalAxis,
26    CategoricalScale,
27    DataRange1d,
28    DatetimeAxis,
29    FactorRange,
30    LinearAxis,
31    LinearScale,
32    LogAxis,
33    LogScale,
34    MercatorAxis,
35    Range1d,
36)
37
38# Module under test
39import bokeh.plotting._plot as bpp # isort:skip
40
41#-----------------------------------------------------------------------------
42# Setup
43#-----------------------------------------------------------------------------
44
45#-----------------------------------------------------------------------------
46# General API
47#-----------------------------------------------------------------------------
48
49#-----------------------------------------------------------------------------
50# Dev API
51#-----------------------------------------------------------------------------
52
53
54class test_get_scale_factor_range:
55    def test_numeric_range_linear_axis() -> None:
56        s = bpp.get_scale(Range1d(), "linear")
57        assert isinstance(s, LinearScale)
58
59        s = bpp.get_scale(Range1d(), "datetime")
60        assert isinstance(s, LinearScale)
61
62        s = bpp.get_scale(Range1d(), "auto")
63        assert isinstance(s, LinearScale)
64
65    def test_numeric_range_log_axis() -> None:
66        s = bpp.get_scale(DataRange1d(), "log")
67        assert isinstance(s, LogScale)
68
69    def test_factor_range() -> None:
70        s = bpp.get_scale(FactorRange(), "auto")
71        assert isinstance(s, CategoricalScale)
72
73
74class Test_get_range:
75    def test_with_None(self) -> None:
76        r = bpp.get_range(None)
77        assert isinstance(r, DataRange1d)
78
79    def test_with_Range(self) -> None:
80        for t in [Range1d, DataRange1d, FactorRange]:
81            rng = t()
82            r = bpp.get_range(rng)
83            assert r is rng
84
85    def test_with_ndarray(self) -> None:
86        r = bpp.get_range(np.array([10, 20]))
87        assert isinstance(r, Range1d)
88        assert r.start == 10
89        assert r.end == 20
90
91    def test_with_too_long_ndarray(self) -> None:
92        with pytest.raises(ValueError):
93            bpp.get_range(np.array([10, 20, 30]))
94
95    def test_with_ndarray_factors(self) -> None:
96        f = np.array(["Crosby", "Stills", "Nash", "Young"])
97        r = bpp.get_range(f)
98        assert isinstance(r, FactorRange)
99        assert r.factors == list(f)
100
101    def test_with_series(self, pd) -> None:
102        r = bpp.get_range(pd.Series([20, 30]))
103        assert isinstance(r, Range1d)
104        assert r.start == 20
105        assert r.end == 30
106
107    def test_with_too_long_series(self, pd) -> None:
108        with pytest.raises(ValueError):
109            bpp.get_range(pd.Series([20, 30, 40]))
110
111    def test_with_string_seq(self) -> None:
112        f = ["foo" ,"end", "baz"]
113        for t in [list, tuple]:
114            r = bpp.get_range(t(f))
115            assert isinstance(r, FactorRange)
116            # FactorRange accepts Seq, but get_range always sets a list copy
117            assert r.factors == f
118
119    def test_with_float_bounds(self) -> None:
120        r = bpp.get_range((1.2, 10))
121        assert isinstance(r, Range1d)
122        assert r.start == 1.2
123        assert r.end == 10
124
125        r = bpp.get_range([1.2, 10])
126        assert isinstance(r, Range1d)
127        assert r.start == 1.2
128        assert r.end == 10
129
130    def test_with_pandas_group(self, pd) -> None:
131        from bokeh.sampledata.iris import flowers
132        g = flowers.groupby('species')
133        r = bpp.get_range(g)
134        assert isinstance(r, FactorRange)
135        assert r.factors == ['setosa', 'versicolor', 'virginica'] # should always be sorted
136
137#-----------------------------------------------------------------------------
138# Private API
139#-----------------------------------------------------------------------------
140
141_RANGES = [Range1d(), DataRange1d(), FactorRange()]
142
143
144class Test__get_axis_class:
145    @pytest.mark.parametrize('range', _RANGES)
146    def test_axis_type_None(self, range) -> None:
147        assert(bpp._get_axis_class(None, range, 0)) == (None, {})
148        assert(bpp._get_axis_class(None, range, 1)) == (None, {})
149
150    @pytest.mark.parametrize('range', _RANGES)
151    def test_axis_type_linear(self, range) -> None:
152        assert(bpp._get_axis_class("linear", range, 0)) == (LinearAxis, {})
153        assert(bpp._get_axis_class("linear", range, 1)) == (LinearAxis, {})
154
155    @pytest.mark.parametrize('range', _RANGES)
156    def test_axis_type_log(self, range) -> None:
157        assert(bpp._get_axis_class("log", range, 0)) == (LogAxis, {})
158        assert(bpp._get_axis_class("log", range, 1)) == (LogAxis, {})
159
160    @pytest.mark.parametrize('range', _RANGES)
161    def test_axis_type_datetime(self, range) -> None:
162        assert(bpp._get_axis_class("datetime", range, 0)) == (DatetimeAxis, {})
163        assert(bpp._get_axis_class("datetime", range, 1)) == (DatetimeAxis, {})
164
165    @pytest.mark.parametrize('range', _RANGES)
166    def test_axis_type_mercator(self, range) -> None:
167        assert(bpp._get_axis_class("mercator", range, 0)) == (MercatorAxis, {'dimension': 'lon'})
168        assert(bpp._get_axis_class("mercator", range, 1)) == (MercatorAxis, {'dimension': 'lat'})
169
170    def test_axis_type_auto(self) -> None:
171        assert(bpp._get_axis_class("auto", FactorRange(), 0)) == (CategoricalAxis, {})
172        assert(bpp._get_axis_class("auto", FactorRange(), 1)) == (CategoricalAxis, {})
173        assert(bpp._get_axis_class("auto", DataRange1d(), 0)) == (LinearAxis, {})
174        assert(bpp._get_axis_class("auto", DataRange1d(), 1)) == (LinearAxis, {})
175        assert(bpp._get_axis_class("auto", Range1d(), 0)) == (LinearAxis, {})
176        assert(bpp._get_axis_class("auto", Range1d(), 1)) == (LinearAxis, {})
177        assert(bpp._get_axis_class("auto", Range1d(start=datetime.datetime(2018, 3, 21)), 0)) == (DatetimeAxis, {})
178        assert(bpp._get_axis_class("auto", Range1d(start=datetime.datetime(2018, 3, 21)), 1)) == (DatetimeAxis, {})
179
180    @pytest.mark.parametrize('range', _RANGES)
181    def test_axis_type_error(self, range) -> None:
182        with pytest.raises(ValueError):
183            bpp._get_axis_class("junk", range, 0)
184        with pytest.raises(ValueError):
185            bpp._get_axis_class("junk", range, 1)
186
187#-----------------------------------------------------------------------------
188# Code
189#-----------------------------------------------------------------------------
190