xpectral 1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xpectral-1.0/LICENSE +21 -0
- xpectral-1.0/PKG-INFO +72 -0
- xpectral-1.0/README.md +27 -0
- xpectral-1.0/pyproject.toml +48 -0
- xpectral-1.0/setup.cfg +4 -0
- xpectral-1.0/tests/test_polars_charts_accessor.py +71 -0
- xpectral-1.0/xpectral/__init__.py +20 -0
- xpectral-1.0/xpectral/charts/__init__.py +17 -0
- xpectral-1.0/xpectral/charts/_decorators.py +73 -0
- xpectral-1.0/xpectral/charts/_figure.py +86 -0
- xpectral-1.0/xpectral/charts/polars_accessors.py +256 -0
- xpectral-1.0/xpectral/charts/theme_manager.py +136 -0
- xpectral-1.0/xpectral/data/__init__.py +16 -0
- xpectral-1.0/xpectral/data/massive.py +97 -0
- xpectral-1.0/xpectral/quant/__init__.py +18 -0
- xpectral-1.0/xpectral/quant/polars_accessors.py +142 -0
- xpectral-1.0/xpectral/quant/polars_expressions.py +39 -0
- xpectral-1.0/xpectral/quant/portfolio.py +82 -0
- xpectral-1.0/xpectral/utils/logger.py +55 -0
- xpectral-1.0/xpectral/utils/rate_limiter.py +52 -0
- xpectral-1.0/xpectral.egg-info/PKG-INFO +72 -0
- xpectral-1.0/xpectral.egg-info/SOURCES.txt +23 -0
- xpectral-1.0/xpectral.egg-info/dependency_links.txt +1 -0
- xpectral-1.0/xpectral.egg-info/requires.txt +7 -0
- xpectral-1.0/xpectral.egg-info/top_level.txt +1 -0
xpectral-1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 BayQuant
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
xpectral-1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xpectral
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: Quant Research Library
|
|
5
|
+
Author: BayQuant
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 BayQuant
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/bayquant/xpectral
|
|
29
|
+
Keywords: finance,quant,bokeh,polars
|
|
30
|
+
Classifier: Programming Language :: Python :: 3
|
|
31
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Operating System :: OS Independent
|
|
34
|
+
Requires-Python: >=3.12
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
License-File: LICENSE
|
|
37
|
+
Requires-Dist: bokeh==3.8.1
|
|
38
|
+
Requires-Dist: massive>=2.0.2
|
|
39
|
+
Requires-Dist: matplotlib>=3.10.7
|
|
40
|
+
Requires-Dist: pandas>=2.3.3
|
|
41
|
+
Requires-Dist: polars>=1.34.0
|
|
42
|
+
Requires-Dist: pyarrow>=21.0.0
|
|
43
|
+
Requires-Dist: python-dotenv>=1.2.1
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
|
|
46
|
+
# Xpectral
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
A quantitative research library that extends **Polars** DataFrames with charting and financial analytics.
|
|
51
|
+
|
|
52
|
+
## Modules
|
|
53
|
+
|
|
54
|
+
- **`xpectral.charts`** — Fluent Bokeh visualization via `df.bokeh.line(...)`, `df.bokeh.scatter(...)`, etc.
|
|
55
|
+
- **`xpectral.quant`** — Financial metrics (returns, volatility, beta) via `pl.col(...).quant.returns()`
|
|
56
|
+
- **`xpectral.data`** — Market data from the Polygon/Massive API with caching and rate limiting
|
|
57
|
+
|
|
58
|
+
## Usage
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import polars as pl
|
|
62
|
+
import xpectral # registers .bokeh and .quant accessors
|
|
63
|
+
|
|
64
|
+
df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
|
|
65
|
+
fig = df.bokeh.line(x="x", y="y")
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Install
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv sync
|
|
72
|
+
```
|
xpectral-1.0/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Xpectral
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
A quantitative research library that extends **Polars** DataFrames with charting and financial analytics.
|
|
6
|
+
|
|
7
|
+
## Modules
|
|
8
|
+
|
|
9
|
+
- **`xpectral.charts`** — Fluent Bokeh visualization via `df.bokeh.line(...)`, `df.bokeh.scatter(...)`, etc.
|
|
10
|
+
- **`xpectral.quant`** — Financial metrics (returns, volatility, beta) via `pl.col(...).quant.returns()`
|
|
11
|
+
- **`xpectral.data`** — Market data from the Polygon/Massive API with caching and rate limiting
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
import polars as pl
|
|
17
|
+
import xpectral # registers .bokeh and .quant accessors
|
|
18
|
+
|
|
19
|
+
df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
|
|
20
|
+
fig = df.bokeh.line(x="x", y="y")
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv sync
|
|
27
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "xpectral"
|
|
7
|
+
version = "1.0"
|
|
8
|
+
description = "Quant Research Library"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = { file = "LICENSE" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "BayQuant" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["finance", "quant", "bokeh", "polars"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
dependencies = [
|
|
24
|
+
"bokeh==3.8.1",
|
|
25
|
+
"massive>=2.0.2",
|
|
26
|
+
"matplotlib>=3.10.7",
|
|
27
|
+
"pandas>=2.3.3",
|
|
28
|
+
"polars>=1.34.0",
|
|
29
|
+
"pyarrow>=21.0.0",
|
|
30
|
+
"python-dotenv>=1.2.1",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[dependency-groups]
|
|
34
|
+
dev = [
|
|
35
|
+
"black", # code formatter
|
|
36
|
+
"ipykernel>=7.0.1", # Jupyter notebook support
|
|
37
|
+
"furo>=2024.0", # Sphinx theme for docs
|
|
38
|
+
"myst-parser>=3.0", # Markdown support in Sphinx docs
|
|
39
|
+
"sphinx>=8.0", # Sphinx documentation generator
|
|
40
|
+
"sphinx-autodoc-typehints>=2.0", # type hint rendering in Sphinx docs
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
Homepage = "https://github.com/bayquant/xpectral"
|
|
45
|
+
|
|
46
|
+
[tool.setuptools.packages.find]
|
|
47
|
+
where = ["."]
|
|
48
|
+
include = ["xpectral*"]
|
xpectral-1.0/setup.cfg
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
import polars as pl
|
|
4
|
+
from bokeh.plotting import figure
|
|
5
|
+
|
|
6
|
+
from xpectral.charts import polars_accessors
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestPolarsBokehAccessor(unittest.TestCase):
|
|
10
|
+
def setUp(self) -> None:
|
|
11
|
+
self.df = pl.DataFrame(
|
|
12
|
+
{
|
|
13
|
+
"x": [1, 2, 3],
|
|
14
|
+
"y": [10, 20, 30],
|
|
15
|
+
"y2": [12, 18, 36],
|
|
16
|
+
"low": [8, 16, 24],
|
|
17
|
+
"high": [14, 24, 40],
|
|
18
|
+
}
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
def test_unknown_glyph_raises(self) -> None:
|
|
22
|
+
with self.assertRaisesRegex(ValueError, "Unknown glyph 'area'"):
|
|
23
|
+
self.df.bokeh.plot("area", glyph_params={"x": "x", "y": "y"})
|
|
24
|
+
|
|
25
|
+
def test_missing_column_fails_through_bokeh_validation(self) -> None:
|
|
26
|
+
with self.assertRaisesRegex(Exception, "missing"):
|
|
27
|
+
self.df.bokeh.plot("line", glyph_params={"x": "x", "y": "missing"})
|
|
28
|
+
|
|
29
|
+
def test_unsupported_figure_param_raises(self) -> None:
|
|
30
|
+
with self.assertRaisesRegex(ValueError, "Unsupported figure_params: not_a_figure_prop"):
|
|
31
|
+
self.df.bokeh.plot(
|
|
32
|
+
"line",
|
|
33
|
+
glyph_params={"x": "x", "y": "y"},
|
|
34
|
+
figure_params={"not_a_figure_prop": 1},
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def test_default_x_uses_generated_index_column(self) -> None:
|
|
38
|
+
df = self.df.drop("x")
|
|
39
|
+
fig = df.bokeh.plot("line", glyph_params={"y": "y"})
|
|
40
|
+
|
|
41
|
+
self.assertEqual(fig.renderers[0].glyph.x, "__index")
|
|
42
|
+
self.assertIn("__index", fig.renderers[0].data_source.column_names)
|
|
43
|
+
self.assertNotIn("__index", df.columns)
|
|
44
|
+
|
|
45
|
+
def test_existing_figure_is_reused_and_updated(self) -> None:
|
|
46
|
+
existing = figure(width=250)
|
|
47
|
+
fig = self.df.bokeh.plot(
|
|
48
|
+
"scatter",
|
|
49
|
+
glyph_params={"x": "x", "y": "y"},
|
|
50
|
+
figure=existing,
|
|
51
|
+
figure_params={"title": "Updated"},
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
self.assertIs(fig, existing)
|
|
55
|
+
self.assertEqual(existing.title.text, "Updated")
|
|
56
|
+
self.assertEqual(len(existing.renderers), 1)
|
|
57
|
+
|
|
58
|
+
def test_accepted_figure_params_api(self) -> None:
|
|
59
|
+
fig_keys = self.df.bokeh.accepted_figure_params()
|
|
60
|
+
self.assertIsInstance(fig_keys, set)
|
|
61
|
+
self.assertIn("title", fig_keys)
|
|
62
|
+
|
|
63
|
+
def test_accepted_figure_params_pattern_filter_returns_set(self) -> None:
|
|
64
|
+
fig_keys = self.df.bokeh.accepted_figure_params(pattern="title")
|
|
65
|
+
self.assertIsInstance(fig_keys, set)
|
|
66
|
+
self.assertTrue(fig_keys)
|
|
67
|
+
self.assertTrue(all("title" in key for key in fig_keys))
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
if __name__ == "__main__":
|
|
71
|
+
unittest.main()
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#-----------------------------------------------------------------------------
|
|
2
|
+
# Imports
|
|
3
|
+
#-----------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
# Standard library imports
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
# Other imports
|
|
9
|
+
from dotenv import load_dotenv
|
|
10
|
+
from . import charts
|
|
11
|
+
from . import data
|
|
12
|
+
from . import quant
|
|
13
|
+
|
|
14
|
+
#-----------------------------------------------------------------------------
|
|
15
|
+
# Globals and constants
|
|
16
|
+
#-----------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
load_dotenv(
|
|
19
|
+
dotenv_path=Path(__file__).resolve().parent / ".env"
|
|
20
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#-----------------------------------------------------------------------------
|
|
2
|
+
# Imports
|
|
3
|
+
#-----------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
# Standard library imports
|
|
6
|
+
|
|
7
|
+
# Other imports
|
|
8
|
+
from .polars_accessors import BokehAccessor
|
|
9
|
+
from .polars_accessors import Figure
|
|
10
|
+
|
|
11
|
+
#-----------------------------------------------------------------------------
|
|
12
|
+
# Globals and constants
|
|
13
|
+
#-----------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"BokehAccessor"
|
|
17
|
+
]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#-----------------------------------------------------------------------------
|
|
2
|
+
# Imports
|
|
3
|
+
#-----------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
# Standard library imports
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
from functools import wraps
|
|
8
|
+
from inspect import Parameter
|
|
9
|
+
from inspect import Signature
|
|
10
|
+
from inspect import signature
|
|
11
|
+
|
|
12
|
+
# Other imports
|
|
13
|
+
from bokeh.plotting._docstring import generate_docstring
|
|
14
|
+
from bokeh.plotting._renderer import create_renderer
|
|
15
|
+
|
|
16
|
+
#-----------------------------------------------------------------------------
|
|
17
|
+
# Globals and constants
|
|
18
|
+
#-----------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
#-----------------------------------------------------------------------------
|
|
21
|
+
# General API
|
|
22
|
+
#-----------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
def glyph_method(glyphclass):
|
|
25
|
+
def decorator(func):
|
|
26
|
+
parameters = glyphclass.parameters()
|
|
27
|
+
|
|
28
|
+
# TODO: send issue so that this signature only takes glyphclass.args instead of [x[0] for x in parameters]
|
|
29
|
+
sigparams = (
|
|
30
|
+
[Parameter("self", Parameter.POSITIONAL_OR_KEYWORD)]
|
|
31
|
+
+ [x[0] for x in parameters]
|
|
32
|
+
+ [Parameter("source", Parameter.KEYWORD_ONLY, default=None)]
|
|
33
|
+
+ [Parameter("kwargs", Parameter.VAR_KEYWORD)]
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
@wraps(func)
|
|
37
|
+
def wrapped(self, *args, **kwargs):
|
|
38
|
+
# Validate positional arguments against the glyph's declared positional field order.
|
|
39
|
+
if len(args) > len(glyphclass._args):
|
|
40
|
+
raise TypeError(f"{func.__name__} takes {len(glyphclass._args)} positional argument but {len(args)} were given")
|
|
41
|
+
# Map positional inputs to their corresponding glyph kwargs by param name.
|
|
42
|
+
for arg, param in zip(args, sigparams[1:]):
|
|
43
|
+
kwargs[param.name] = arg
|
|
44
|
+
# Default source comes from the accessor unless explicitly provided.
|
|
45
|
+
kwargs.setdefault("source", self.source)
|
|
46
|
+
# Preserve any coordinate context passed through a custom Figure subclass.
|
|
47
|
+
if self.coordinates is not None:
|
|
48
|
+
kwargs.setdefault("coordinates", self.coordinates)
|
|
49
|
+
# Inspect/create synthetic fields on the source when required by the glyph.
|
|
50
|
+
source = kwargs["source"]
|
|
51
|
+
n = len(next(iter(source.data.values()), ()))
|
|
52
|
+
# If x is required but missing, inject a 1..n index column into source and reference it by name.
|
|
53
|
+
if "x" in glyphclass._args and "x" not in kwargs and "x" not in source.data:
|
|
54
|
+
source.data["x"] = list(range(1, n + 1))
|
|
55
|
+
kwargs["x"] = "x"
|
|
56
|
+
# If y is required but missing, inject a 1..n index column into source and reference it by name.
|
|
57
|
+
if "y" in glyphclass._args and "y" not in kwargs and "y" not in source.data:
|
|
58
|
+
source.data["y"] = list(range(1, n + 1))
|
|
59
|
+
kwargs["y"] = "y"
|
|
60
|
+
# Delegate to Bokeh with normalized kwargs and possibly augmented source columns.
|
|
61
|
+
return create_renderer(glyphclass, self.plot, **kwargs)
|
|
62
|
+
|
|
63
|
+
wrapped.__signature__ = Signature(parameters=sigparams, return_annotation=signature(func).return_annotation)
|
|
64
|
+
|
|
65
|
+
wrapped.__doc__ = generate_docstring(glyphclass, parameters, func.__doc__)
|
|
66
|
+
|
|
67
|
+
return wrapped
|
|
68
|
+
|
|
69
|
+
return decorator
|
|
70
|
+
|
|
71
|
+
#-----------------------------------------------------------------------------
|
|
72
|
+
# Private API
|
|
73
|
+
#-----------------------------------------------------------------------------
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#-----------------------------------------------------------------------------
|
|
2
|
+
# Imports
|
|
3
|
+
#-----------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
# Standard library imports
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
# Other imports
|
|
9
|
+
from bokeh.models import Plot
|
|
10
|
+
from bokeh.plotting._figure import FigureOptions
|
|
11
|
+
from bokeh.plotting._plot import get_range
|
|
12
|
+
from bokeh.plotting._plot import get_scale
|
|
13
|
+
from bokeh.plotting._plot import process_axis_and_grid
|
|
14
|
+
from bokeh.plotting._tools import process_active_tools
|
|
15
|
+
from bokeh.plotting._tools import process_tools_arg
|
|
16
|
+
|
|
17
|
+
#-----------------------------------------------------------------------------
|
|
18
|
+
# Globals and constants
|
|
19
|
+
#-----------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
__all__ = ["Figure"]
|
|
22
|
+
|
|
23
|
+
#-----------------------------------------------------------------------------
|
|
24
|
+
# General API
|
|
25
|
+
#-----------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
class Figure(Plot):
|
|
28
|
+
|
|
29
|
+
def __init__(self, *arg, **kwargs) -> None:
|
|
30
|
+
opts = FigureOptions(kwargs)
|
|
31
|
+
|
|
32
|
+
names = self.properties()
|
|
33
|
+
for name in kwargs.keys():
|
|
34
|
+
if name not in names:
|
|
35
|
+
self._raise_attribute_error_with_matches(name, names | opts.properties())
|
|
36
|
+
|
|
37
|
+
super().__init__(*arg, **kwargs)
|
|
38
|
+
|
|
39
|
+
self.x_range = get_range(opts.x_range)
|
|
40
|
+
self.y_range = get_range(opts.y_range)
|
|
41
|
+
|
|
42
|
+
self.x_scale = get_scale(self.x_range, opts.x_axis_type)
|
|
43
|
+
self.y_scale = get_scale(self.y_range, opts.y_axis_type)
|
|
44
|
+
|
|
45
|
+
process_axis_and_grid(
|
|
46
|
+
self,
|
|
47
|
+
opts.x_axis_type,
|
|
48
|
+
opts.x_axis_location,
|
|
49
|
+
opts.x_minor_ticks,
|
|
50
|
+
opts.x_axis_label,
|
|
51
|
+
self.x_range,
|
|
52
|
+
0,
|
|
53
|
+
)
|
|
54
|
+
process_axis_and_grid(
|
|
55
|
+
self,
|
|
56
|
+
opts.y_axis_type,
|
|
57
|
+
opts.y_axis_location,
|
|
58
|
+
opts.y_minor_ticks,
|
|
59
|
+
opts.y_axis_label,
|
|
60
|
+
self.y_range,
|
|
61
|
+
1,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
tool_objs, tool_map = process_tools_arg(self, opts.tools, opts.tooltips)
|
|
65
|
+
self.add_tools(*tool_objs)
|
|
66
|
+
process_active_tools(
|
|
67
|
+
self.toolbar,
|
|
68
|
+
tool_map,
|
|
69
|
+
opts.active_drag,
|
|
70
|
+
opts.active_inspect,
|
|
71
|
+
opts.active_scroll,
|
|
72
|
+
opts.active_tap,
|
|
73
|
+
opts.active_multi,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def plot(self):
|
|
78
|
+
return self
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def coordinates(self):
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
#-----------------------------------------------------------------------------
|
|
85
|
+
# Private API
|
|
86
|
+
#-----------------------------------------------------------------------------
|