diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 000000000..17dc3c414 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,14 @@ +[run] +omit = + pyecharts/render/templates/* + setup.py + install.py + test.py + test/* + +[report] +show_missing = True +omit = + pyecharts/render/templates/* + setup.py + install.py \ No newline at end of file diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml new file mode 100644 index 000000000..7b4923a45 --- /dev/null +++ b/.github/workflows/python-app.yml @@ -0,0 +1,59 @@ +name: pyecharts CI + +on: + push: + paths-ignore: + - '**/*.md' + pull_request: + paths-ignore: + - '**/*.md' + +jobs: + build: + strategy: + # Allows for matrix sub-jobs to fail without canceling the rest + fail-fast: false + matrix: + os: + - ubuntu-latest + - macos-latest + - windows-latest + python-version: + - "3.14" + - "3.13" + - "3.12" + - "3.11" + - "3.10" + - "3.9" + - "3.8" + - "3.7" + exclude: # Python < v3.8 does not support Apple Silicon ARM64. + - python-version: "3.7" + os: macos-latest + - python-version: "3.7" + os: ubuntu-latest + include: # So run those legacy versions on Intel CPUs. + # No ci env to test macos 13 with python3.7 + #- python-version: "3.7" + # os: macos-13 + - python-version: "3.7" + os: ubuntu-22.04 + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip setuptools + pip install -r requirements.txt + pip install -r test/requirements.txt + - name: Run unit test + run: | + pip install . + pytest -v --cov-config=pyproject.toml --cov=./ test/ + - name: Codecov + run: | + codecov diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6bacc1e65..000000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -sudo: false -language: python -notifications: - email: - recipients: - - chenjiandongx@qq.com - on_success: always # default: change - on_failure: always # default: always -python: - - "3.8-dev" - - "3.8" - - "3.7" - - "3.6" -before_install: - - pip install -r test/requirements.txt -script: - - python setup.py install - - bash test.sh -after_success: - cd test && codecov - diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..0f153c65d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,294 @@ +# AGENTS.md + +This file contains guidelines for agents working on the pyecharts project. + +## Build/Lint/Test Commands + +### Running Tests + +The project uses multiple testing frameworks. Here are the commands to run tests: + +1. **Run all tests**: + ```bash + make test + # or + python test.py + # or + nose2 --with-coverage --coverage pyecharts --coverage-config .coveragerc -s test + # or + pytest -cov-config=.coveragerc --cov=./ test/ + ``` + +2. **Run a single test file**: + ```bash + # Using pytest (recommended) + pytest test/test_chart.py + + # Using nose2 + nose2 --with-coverage --coverage pyecharts --coverage-config .coveragerc test.test_chart + ``` + +3. **Run a specific test method**: + ```bash + # Using pytest + pytest test/test_chart.py::TestChartClass::test_chart_dark_mode + + # Using nose2 + nose2 --with-coverage --coverage pyecharts --coverage-config .coveragerc test.test_chart.TestChartClass.test_chart_dark_mode + ``` + +4. **Run tests with verbose output**: + ```bash + pytest -v test/test_chart.py + ``` + +5. **Run tests with coverage reporting**: + ```bash + pytest -v --cov=./ --cov-report=html test/test_chart.py + ``` + +### Linting + +1. **Run linter**: + ```bash + make lint + # or + flake8 --exclude=build,images,example,examples --max-line-length=89 --ignore=F401 + ``` + +2. **Lint a specific file**: + ```bash + flake8 --exclude=build,images,example,examples --max-line-length=89 --ignore=F401 test/test_chart.py + ``` + +### Formatting + +The project uses black and isort for code formatting: + +1. **Run black formatter**: + ```bash + black . + ``` + +2. **Run isort for imports**: + ```bash + isort . + ``` + +### Building + +1. **Build the package**: + ```bash + python setup.py sdist bdist_wheel + ``` + +2. **Upload to PyPI**: + ```bash + make upload + # This runs the UploadCommand defined in setup.py + ``` + +## Code Style Guidelines + +### Imports + +1. **Import organization**: + - Standard library imports + - Related third party imports + - Local application/library specific imports + +2. **Import style**: + ```python + # Good + from pyecharts import options as opts + from pyecharts.charts import Line, Bar + + # Avoid + from pyecharts.options import * + import pyecharts.charts.Line + ``` + +3. **Use aliases** for commonly used modules: + ```python + import pyecharts.options as opts + import pyecharts.globals as globals + ``` + +### Formatting + +1. **Line length**: 89 characters max (as specified in flake8 command) + +2. **Indentation**: 4 spaces (no tabs) + +3. **Quotes**: Use double quotes " for strings, single quotes ' for char literals + +4. **Blank lines**: + - Top-level functions and classes: 2 blank lines + - Methods within a class: 1 blank line + +5. **Use black formatter** to ensure consistent code style + +### Naming Conventions + +1. **Variables and functions**: snake_case + ```python + def add_yaxis(self, series_name, y_axis, *args, **kwargs): + pass + ``` + +2. **Classes**: PascalCase + ```python + class TestChartClass(unittest.TestCase): + pass + ``` + +3. **Constants**: UPPER_CASE + ```python + MAX_RETRIES = 3 + ``` + +4. **Private members**: prefix with _ + ```python + def _internal_method(self): + pass + ``` + +### Error Handling + +1. **Use exceptions** for error conditions, not return codes + +2. **Be specific** with exception types: + ```python + try: + result = do_something() + except ValueError as e: + logger.error(f"Invalid value: {e}") + raise + except RuntimeError as e: + logger.error(f"Runtime error: {e}") + raise + ``` + +3. **Don't catch all exceptions** indiscriminately: + ```python + # Avoid + try: + do_something() + except: + pass + + # Prefer + try: + do_something() + except SpecificError: + handle_specific_error() + ``` + +### Testing Guidelines + +1. **Test structure**: + - Use unittest framework with TestCase classes + - Group related tests in classes + - Use descriptive test method names + +2. **Test naming**: + ```python + def test_chart_dark_mode(self): + # Tests a specific feature + + def test_chart_line_style_opts(self): + # Tests a specific option + ``` + +3. **Use mocking** for external dependencies: + ```python + @patch("pyecharts.render.engine.write_utf8_html_file") + def test_chart_dark_mode(self, fake_writer): + # Test code here + ``` + +4. **Test coverage**: + - Aim for high test coverage + - Test both success and failure cases + - Test edge cases + +### Documentation + +1. **Docstrings**: + - Use Google-style docstrings + - Include Args, Returns, and Raises sections when applicable + + ```python + def add_yaxis(self, series_name, y_axis, color=None): + """Add a series to the chart. + + Args: + series_name (str): Name of the series. + y_axis (list): Data values. + color (str, optional): Color of the series. Defaults to None. + + Returns: + Chart: The chart instance for method chaining. + """ + ``` + +2. **Comments**: + - Use comments to explain "why", not "what" + - Keep comments up-to-date with code changes + +### Best Practices + +1. **Method chaining**: The library supports method chaining, so return self in methods that modify the object: + ```python + def add_xaxis(self, xaxis_data): + self.options["xAxis"][0]["data"] = xaxis_data + return self # Enable method chaining + ``` + +2. **Type hints**: Use type hints for better code documentation and IDE support: + ```python + def add_yaxis(self, series_name: str, y_axis: list) -> "Base": + # method implementation + return self + ``` + +3. **Immutable options**: When adding options, don't modify the original option objects: + ```python + # Good - create a copy + self.options = deepcopy(self.options) + + # Or use dict constructor + new_opts = dict(old_opts) + ``` + +4. **Performance**: Be mindful of performance when processing large datasets. + +5. **Backward compatibility**: When making changes, consider backward compatibility for existing users. + +## Development Workflow + +1. **Make changes** to the code +2. **Run tests** to ensure nothing is broken: + ```bash + make test + ``` +3. **Lint the code**: + ```bash + make lint + ``` +4. **Format the code**: + ```bash + black . + isort . + ``` +5. **Commit and push** your changes + +## Additional Notes + +- The project uses both pytest and nose2 for testing. pytest is recommended for running individual tests. +- Coverage is configured in .coveragerc to exclude test files and templates. +- The build process is defined in setup.py with a custom UploadCommand for publishing to PyPI. +- JavaScript dependencies are managed through the js_dependencies attribute in Base class. +- The default locale is Chinese (ZH), but can be changed to English (EN). +- Charts support dark mode via set_dark_mode() method. +- Use the render() method to generate HTML files, and render_embed() for embedding charts. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..c32b0ce1c --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +# Variables +PACKAGE_NAME = pyecharts + +# Targets +.PHONY: help +help: + @echo "Please use \`make \` where is one of" + @echo " test -- run local unit tests" + @echo " build -- build the package" + @echo " lint -- run flake8 for code linting" + @echo " clean -- clean up temporary files" + +.PHONY: test +test: + @uv run pytest -v --cov-config=pyproject.toml --cov=./ test/ + +.PHONY: build +build: + @uv build + +.PHONY: lint +lint: + @uv run flake8 --exclude=build,images,example,examples,.venv --max-line-length=89 --ignore=F401,F824 + +.PHONY: clean +clean: + @rm -rf dist build $(PACKAGE_NAME).egg-info + @rm -f .coverage coverage.xml tests/.coverage tests/coverage.xml resize_render.html diff --git a/README.en.md b/README.en.md index 69c5495fd..9fe2836d6 100644 --- a/README.en.md +++ b/README.en.md @@ -6,11 +6,8 @@ Python ❤️ ECharts = pyecharts

- - Travis Build Status - - - Appveyor Build Status + + Github Actions Status Codecov @@ -36,18 +33,45 @@ ## 📣 Introduction -[Apache ECharts (incubating)](https://github.com/apache/incubator-echarts) is easy-to-use, highly interactive and highly performant javascript visualization library under Apache license. Since its first public release in 2013, it now dominates over 74% of Chinese web front-end market. Yet Python is an expressive language and is loved by data science community. Combining the strength of both technologies, [pyecharts](https://github.com/pyecharts/pyecharts) is born. +[Apache ECharts](https://github.com/apache/echarts) is easy-to-use, highly interactive and highly performant javascript visualization library under Apache license. Since its first public release in 2013, it now dominates over 74% of Chinese web front-end market. Yet Python is an expressive language and is loved by data science community. Combining the strength of both technologies, [pyecharts](https://github.com/pyecharts/pyecharts) is born. + +* **`pyecharts like` visualization projects** + * [py-vchart](https://github.com/VisActor/py-vchart) + * [py-antv](https://github.com/sunhailin-Leo/pyantv) ## ✨ Feature highlights * Simple API, Sleek and method chaining * Support 30 + popular charts -* Suppot data science tools: Jupyter Notebook, JupyterLab, nteract +* Support data science tools: Jupyter Notebook, JupyterLab, nteract, [marimo](https://github.com/marimo-team/marimo) * Integrate with Flask,Django at ease * Easy to use and highly configurable * Detailed documentation and examples. * More than 400+ geomaps assets for geograpic information processing +## ⏳ Version + +v0.5.x is not compatible with V1, which is a completely new version, see [ISSUE#892](https://github.com/pyecharts/pyecharts/issues/892), [ISSUE#1033](https://github.com/pyecharts/). pyecharts/issues/1033). + +### V0.5.x + +> Support for Python 2.7, 3.4+ + +At the discretion of the development team, version 0.5.x will no longer be maintained. Version 0.5.x code is located in the *05x* branch and documentation is located at [05x-docs.pyecharts.org](http://05x-docs.pyecharts.org). + +### V1 + +> Python 3.7+ only + +The new version series will start with v1.0.0, documented at [pyecharts.org](https://pyecharts.org); examples at [gallery.pyecharts.org](https://gallery.pyecharts.org) + +### V2 + +> Python 3.7+ only + +The new version is based on Echarts 5.4.1+ for rendering, and the documentation and examples are in the same location as V1. + + ## 🔰 Installation **pip install** @@ -145,7 +169,7 @@ make_snapshot(bar.render(), "bar.png") timeline -For more documentaiton, please visit +For more documentation, please visit * [Chinese documentation](https://pyecharts.org/#/zh-cn/) * [English Documentation](https://pyecharts.org/#/en-us/) diff --git a/README.md b/README.md index 5574abcd4..55d9aefa9 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,8 @@ Python ❤️ ECharts = pyecharts

- - Travis Build Status - - - Appveyor Build Status + + Github Actions Status Codecov @@ -26,7 +23,7 @@ PyPI - Format - + Contributions welcome @@ -38,13 +35,17 @@ ## 📣 简介 -[Apache ECharts (incubating)](https://github.com/apache/incubator-echarts) 是一个由百度开源的数据可视化,凭借着良好的交互性,精巧的图表设计,得到了众多开发者的认可。而 Python 是一门富有表达力的语言,很适合用于数据处理。当数据分析遇上数据可视化时,[pyecharts](https://github.com/pyecharts/pyecharts) 诞生了。 +[Apache ECharts](https://github.com/apache/echarts) 是一个由百度开源的数据可视化,凭借着良好的交互性,精巧的图表设计,得到了众多开发者的认可。而 Python 是一门富有表达力的语言,很适合用于数据处理。当数据分析遇上数据可视化时,[pyecharts](https://github.com/pyecharts/pyecharts) 诞生了。 + +* **`pyecharts like` 的可视化项目** + * [py-vchart](https://github.com/VisActor/py-vchart) + * [py-antv](https://github.com/sunhailin-Leo/pyantv) ## ✨ 特性 * 简洁的 API 设计,使用如丝滑般流畅,支持链式调用 * 囊括了 30+ 种常见图表,应有尽有 -* 支持主流 Notebook 环境,Jupyter Notebook 和 JupyterLab +* 支持主流 Notebook 环境,Jupyter Notebook、JupyterLab 和 [marimo](https://github.com/marimo-team/marimo) * 可轻松集成至 Flask,Sanic,Django 等主流 Web 框架 * 高度灵活的配置项,可轻松搭配出精美的图表 * 详细的文档和示例,帮助开发者更快的上手项目 @@ -56,16 +57,22 @@ v0.5.x 和 V1 间不兼容,V1 是一个全新的版本,详见 [ISSUE#892](ht ### V0.5.x -> 支持 Python2.7,3.4+ +> 支持 Python 2.7,3.4+ 经开发团队决定,0.5.x 版本将不再进行维护,0.5.x 版本代码位于 *05x* 分支,文档位于 [05x-docs.pyecharts.org](http://05x-docs.pyecharts.org)。 ### V1 -> 仅支持 Python3.6+ +> 仅支持 Python 3.7+ 新版本系列将从 v1.0.0 开始,文档位于 [pyecharts.org](https://pyecharts.org);示例位于 [gallery.pyecharts.org](https://gallery.pyecharts.org) +### V2 + +> 仅支持 Python 3.7+ + +新版本基于 Echarts 5.4.1+ 进行渲染, 文档和示例位置与 V1 相同 + ## 🔰 安装 **pip 安装** @@ -234,16 +241,6 @@ pyecharts 主要由以下几位开发者开发维护 更多贡献者信息可以访问 [pyecharts/graphs/contributors](https://github.com/pyecharts/pyecharts/graphs/contributors) -## 💌 捐赠 - -开发和维护 pyecharts 花费了我巨大的心力,如果你觉得项目帮助到您,请认真考虑请作者喝一杯咖啡 😄 - -| 微信二维码 | 支付宝二维码 | -| -------- | ---------- | -| wechat-code | alipay-code | - -如果其他开发者帮助到了您,也可以请他们喝咖啡 [捐赠通道](http://pyecharts.org/#/zh-cn/donate) - ## 💡 贡献 期待能有更多的开发者参与到 pyecharts 的开发中来,我们会保证尽快 Reivew PR 并且及时回复。但提交 PR 请确保 diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index ad3f1e948..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,18 +0,0 @@ -environment: - - matrix: - - PYTHON: "C:\\Python36-x64" - PYTHON_VERSION: "3.6" - - PYTHON: "C:\\Python37-x64" - PYTHON_VERSION: "3.7" - - PYTHON: "C:\\Python38-x64" - PYTHON_VERSION: "3.8" - -install: - - "%PYTHON%\\python.exe -m pip install -r requirements.txt" - - cd test - - "%PYTHON%\\python.exe -m pip install -r requirements.txt" -build: off - -test_script: - - "%PYTHON%/Scripts/nosetests --with-coverage --cover-package pyecharts --cover-package test && cd .. && %PYTHON%/Scripts/flake8 --exclude build --max-line-length 89 --ignore=F401" diff --git a/make.bat b/make.bat deleted file mode 100644 index 0ae7d7984..000000000 --- a/make.bat +++ /dev/null @@ -1,2 +0,0 @@ -cd test -nosetests --with-coverage --cover-package pyecharts --cover-package test && cd .. && flake8 --exclude build --max-line-length 89 --ignore=F401 diff --git a/pyecharts/_version.py b/pyecharts/_version.py index 957cb16d7..ae17e2131 100644 --- a/pyecharts/_version.py +++ b/pyecharts/_version.py @@ -1,2 +1,2 @@ -__version__ = "1.9.0" -__author__ = "chenjiandongx" +__version__ = "2.1.0" +__author__ = "chenjiandongx" diff --git a/pyecharts/charts/__init__.py b/pyecharts/charts/__init__.py index efc966e77..42d20cfec 100644 --- a/pyecharts/charts/__init__.py +++ b/pyecharts/charts/__init__.py @@ -1,17 +1,22 @@ # basic Charts +from ..charts.basic_charts.amap import AMap from ..charts.basic_charts.bar import Bar from ..charts.basic_charts.bmap import BMap from ..charts.basic_charts.boxplot import Boxplot from ..charts.basic_charts.calendar import Calendar +from ..charts.basic_charts.chord import Chord +from ..charts.basic_charts.custom import Custom from ..charts.basic_charts.effectscatter import EffectScatter from ..charts.basic_charts.funnel import Funnel from ..charts.basic_charts.gauge import Gauge from ..charts.basic_charts.geo import Geo +from ..charts.basic_charts.gmap import GMap from ..charts.basic_charts.graph import Graph from ..charts.basic_charts.heatmap import HeatMap from ..charts.basic_charts.kline import Kline from ..charts.basic_charts.line import Line from ..charts.basic_charts.liquid import Liquid +from ..charts.basic_charts.lmap import LMap from ..charts.basic_charts.map import Map from ..charts.basic_charts.parallel import Parallel from ..charts.basic_charts.pictorialbar import PictorialBar @@ -34,7 +39,9 @@ # 3d charts from ..charts.three_axis_charts.bar3D import Bar3D +from ..charts.three_axis_charts.graph_gl import GraphGL from ..charts.three_axis_charts.line3D import Line3D +from ..charts.three_axis_charts.lines3D import Lines3D from ..charts.three_axis_charts.map3D import Map3D from ..charts.three_axis_charts.map_globe import MapGlobe from ..charts.three_axis_charts.scatter3D import Scatter3D diff --git a/pyecharts/charts/base.py b/pyecharts/charts/base.py index 3c9d724d1..f75ebfa06 100644 --- a/pyecharts/charts/base.py +++ b/pyecharts/charts/base.py @@ -1,15 +1,13 @@ import datetime import uuid -import warnings import simplejson as json from jinja2 import Environment from ..commons import utils -from ..globals import CurrentConfig, RenderType, ThemeType, WarningType -from ..options import InitOpts -from ..options.global_options import AnimationOpts -from ..options.series_options import BasicOpts +from ..globals import CurrentConfig, Locale, RenderType, ThemeType, DefaultLocale +from ..options import InitOpts, RenderOpts +from ..options.series_options import BasicOpts, AnimationOpts from ..render import engine from ..types import Optional, Sequence, Union from .mixins import ChartMixin @@ -21,25 +19,64 @@ class Base(ChartMixin): part of the initialization parameters and common methods """ - def __init__(self, init_opts: Union[InitOpts, dict] = InitOpts()): + def __init__( + self, + init_opts: Union[InitOpts, dict] = InitOpts(), + render_opts: Union[RenderOpts, dict] = RenderOpts(), + ): _opts = init_opts if isinstance(init_opts, InitOpts): _opts = init_opts.opts + _render_opts = render_opts + if isinstance(render_opts, RenderOpts): + _render_opts = render_opts.opts + self.width = _opts.get("width", "900px") self.height = _opts.get("height", "500px") + self.horizontal_center = ( + "text-align:center; margin: auto" + if _opts.get("is_horizontal_center", False) + else "" + ) self.renderer = _opts.get("renderer", RenderType.CANVAS) + self.locale = ( + CurrentConfig.LOCALE if + getattr(Locale, CurrentConfig.LOCALE, False) + else DefaultLocale + ) self.page_title = _opts.get("page_title", CurrentConfig.PAGE_TITLE) self.theme = _opts.get("theme", ThemeType.WHITE) self.chart_id = _opts.get("chart_id") or uuid.uuid4().hex + self.fill_bg = _opts.get("fill_bg", False) + self.bg_color = _opts.get("bg_color") self.options: dict = {} + self.render_options: dict = {} self.js_host: str = _opts.get("js_host") or CurrentConfig.ONLINE_HOST self.js_functions: utils.OrderedSet = utils.OrderedSet() self.js_dependencies: utils.OrderedSet = utils.OrderedSet("echarts") - self.options.update(backgroundColor=_opts.get("bg_color")) - self.options.update(_opts.get("animationOpts", AnimationOpts()).opts) + self.js_events: utils.OrderedSet = utils.OrderedSet() + self.options.update(backgroundColor=self.bg_color) + if isinstance(_opts.get("animationOpts", AnimationOpts()), dict): + self.options.update(_opts.get("animationOpts", AnimationOpts().opts)) + else: + self.options.update(_opts.get("animationOpts", AnimationOpts()).opts) + self.options.update(aria=_opts.get("ariaOpts")) + self._is_geo_chart: bool = False + self._geo_json_name: Optional[str] = None + self._geo_json: Optional[dict] = None + + self.render_options.update(embed_js=bool(_render_opts.get("embed_js"))) + self._render_cache: dict = dict() + + def use_echarts_stat(self): + self.js_dependencies.add("echarts-stat") + return self + + def get_chart_id(self) -> str: + return self.chart_id def get_options(self) -> dict: return utils.remove_key_with_none_value(self.options) @@ -88,6 +125,12 @@ def _prepare_render(self): self.json_contents = self.dump_options() self._use_theme() + self._render_cache.clear() + if self.render_options.get("embed_js"): + self._render_cache[ + "javascript" + ] = self.load_javascript().load_javascript_contents() + def default(o): if isinstance(o, (datetime.date, datetime.datetime)): diff --git a/pyecharts/charts/basic_charts/amap.py b/pyecharts/charts/basic_charts/amap.py new file mode 100644 index 000000000..e51efdcbc --- /dev/null +++ b/pyecharts/charts/basic_charts/amap.py @@ -0,0 +1,91 @@ +from ... import options as opts +from ... import types +from ...charts.basic_charts.geo import GeoChartBase +from ...commons.utils import OrderedSet, JsCode +from ...exceptions import NonexistentCoordinatesException +from ...globals import ChartType + +AMAP_API = "https://webapi.amap.com/maps?v=2.0&key={}&plugin=AMap.Scale,AMap.ToolBar" + + +class AMap(GeoChartBase): + """ + <<< AMap(GaoDe) coordinate system >>> + + Support scatter plot, line. + """ + + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + is_ignore_nonexistent_coord: bool = False, + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) + self.js_dependencies.add("amap") + self._is_geo_chart = True + self._coordinate_system: types.Optional[str] = "amap" + self.amap_js_functions: OrderedSet = OrderedSet() + self._is_ignore_nonexistent_coord = is_ignore_nonexistent_coord + + def _feed_data(self, data_pair: types.Sequence, type_: str) -> types.Sequence: + result = [] + type_list = [ChartType.LINES, ChartType.CUSTOM] + if type_ in type_list: + result = data_pair + else: + for n, v in data_pair: + try: + lng, lat = self.get_coordinate(n) + result.append({"name": n, "value": [lng, lat, v]}) + except TypeError as err: + if self._is_ignore_nonexistent_coord is not True: + raise NonexistentCoordinatesException(err, (n, v)) + return result + + def add_schema( + self, + amap_ak: str, + center: types.Sequence, + zoom: types.Union[types.Numeric, str] = None, + is_enable_resize: bool = True, + map_style: types.Optional[dict] = None, + is_render_on_map: bool = True, + is_layer_interactive: bool = True, + is_large: bool = False, + ): + self.js_dependencies.add(AMAP_API.format(amap_ak)) + self.options.update( + amap={ + "center": center, + "viewMode": "3D", # default + "zoom": zoom, + "resizeEnable": is_enable_resize, + "mapStyle": map_style, + "renderOnMoving": is_render_on_map, + "echartsLayerInteractive": is_layer_interactive, + "largeMode": is_large, + } + ) + if is_layer_interactive: + self.amap_js_functions.add( + "amapComponent.setEChartsLayerInteractive(true);" + ) + + return self + + def add_control_panel( + self, + is_add_satellite_layer: bool = False, + is_add_road_net_layer: bool = False, + ): + if is_add_satellite_layer: + self.amap_js_functions.add( + "amap.add(new AMap.TileLayer.Satellite());", + ) + if is_add_road_net_layer: + self.amap_js_functions.add( + "amap.add(new AMap.TileLayer.RoadNet());", + ) + + return self diff --git a/pyecharts/charts/basic_charts/bar.py b/pyecharts/charts/basic_charts/bar.py index 59612d68c..370be4804 100644 --- a/pyecharts/charts/basic_charts/bar.py +++ b/pyecharts/charts/basic_charts/bar.py @@ -17,14 +17,24 @@ def add_yaxis( series_name: str, y_axis: types.Sequence[types.Union[types.Numeric, opts.BarItem, dict]], *, - is_selected: bool = True, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, xaxis_index: types.Optional[types.Numeric] = None, yaxis_index: types.Optional[types.Numeric] = None, + polar_index: types.Optional[types.Numeric] = None, + is_round_cap: types.Optional[bool] = None, + color_by: types.Optional[str] = None, is_legend_hover_link: bool = True, color: types.Optional[str] = None, + is_realtime_sort: bool = False, is_show_background: bool = False, background_style: types.Union[types.BarBackground, dict, None] = None, stack: types.Optional[str] = None, + stack_strategy: types.Optional[str] = "samesign", + stack_order: types.Optional[str] = None, + sampling: types.Optional[str] = None, + cursor: types.Optional[str] = "pointer", bar_width: types.Union[types.Numeric, str] = None, bar_max_width: types.Union[types.Numeric, str] = None, bar_min_width: types.Union[types.Numeric, str] = None, @@ -33,6 +43,9 @@ def add_yaxis( gap: types.Optional[str] = "30%", is_large: bool = False, large_threshold: types.Numeric = 400, + progressive: types.Optional[types.Numeric] = None, + progressive_threshold: types.Optional[types.Numeric] = None, + progressive_chunk_mode: types.Optional[str] = None, dimensions: types.Union[types.Sequence, None] = None, series_layout_by: str = "column", dataset_index: types.Numeric = 0, @@ -42,12 +55,16 @@ def add_yaxis( label_opts: types.Label = opts.LabelOpts(), markpoint_opts: types.MarkPoint = None, markline_opts: types.MarkLine = None, + markarea_opts: types.MarkArea = None, tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, + blur_opts: types.Blur = None, + select_opts: types.Select = None, encode: types.Union[types.JSFunc, dict, None] = None, ): self._append_color(color) - self._append_legend(series_name, is_selected) + self._append_legend(series_name) if self.options.get("dataset") is not None: y_axis = None @@ -56,13 +73,24 @@ def add_yaxis( { "type": ChartType.BAR, "name": series_name, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, "xAxisIndex": xaxis_index, "yAxisIndex": yaxis_index, + "polarIndex": polar_index, + "roundCap": is_round_cap, + "colorBy": color_by, "legendHoverLink": is_legend_hover_link, "data": y_axis, + "realtimeSort": is_realtime_sort, "showBackground": is_show_background, "backgroundStyle": background_style, "stack": stack, + "stackStrategy": stack_strategy, + "stackOrder": stack_order, + "sampling": sampling, + "cursor": cursor, "barWidth": bar_width, "barMaxWidth": bar_max_width, "barMinWidth": bar_min_width, @@ -71,6 +99,9 @@ def add_yaxis( "barGap": gap, "large": is_large, "largeThreshold": large_threshold, + "progressive": progressive, + "progressiveThreshold": progressive_threshold, + "progressiveChunkMode": progressive_chunk_mode, "dimensions": dimensions, "seriesLayoutBy": series_layout_by, "datasetIndex": dataset_index, @@ -80,8 +111,12 @@ def add_yaxis( "label": label_opts, "markPoint": markpoint_opts, "markLine": markline_opts, + "markArea": markarea_opts, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, + "blur": blur_opts, + "select": select_opts, "encode": encode, } ) diff --git a/pyecharts/charts/basic_charts/bmap.py b/pyecharts/charts/basic_charts/bmap.py index 1d8a3ee07..bf1e29f9c 100644 --- a/pyecharts/charts/basic_charts/bmap.py +++ b/pyecharts/charts/basic_charts/bmap.py @@ -20,8 +20,9 @@ def __init__( self, init_opts: types.Init = opts.InitOpts(), is_ignore_nonexistent_coord: bool = False, + render_opts: types.RenderInit = opts.RenderOpts(), ): - super().__init__(init_opts=init_opts) + super().__init__(init_opts=init_opts, render_opts=render_opts) self.js_dependencies.add("bmap") self._is_geo_chart = True self._coordinate_system: types.Optional[str] = "bmap" diff --git a/pyecharts/charts/basic_charts/boxplot.py b/pyecharts/charts/basic_charts/boxplot.py index b53d242c2..5d52e1813 100644 --- a/pyecharts/charts/basic_charts/boxplot.py +++ b/pyecharts/charts/basic_charts/boxplot.py @@ -16,30 +16,75 @@ class Boxplot(RectChart): def add_yaxis( self, series_name: str, - y_axis: types.Sequence[types.Union[opts.BoxplotItem, dict]], + y_axis: types.Optional[ + types.Sequence[types.Union[opts.BoxplotItem, dict]] + ] = None, *, - is_selected: bool = True, + chart_type: str = ChartType.BOXPLOT, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, xaxis_index: types.Optional[types.Numeric] = None, + xaxis_id: types.Optional[types.Numeric] = None, yaxis_index: types.Optional[types.Numeric] = None, + yaxis_id: types.Optional[types.Numeric] = None, + dataset_index: types.Optional[types.Numeric] = None, + color_by: types.Optional[str] = None, + is_legend_hover_link: bool = True, + is_hover_animation: bool = True, + layout: types.Optional[str] = None, + box_width: types.Optional[types.Sequence] = None, + selected_mode: types.Union[bool, str] = False, + dimensions: types.Union[types.Sequence, None] = None, label_opts: types.Label = opts.LabelOpts(), markpoint_opts: types.MarkPoint = opts.MarkPointOpts(), markline_opts: types.MarkLine = opts.MarkLineOpts(), + markarea_opts: types.MarkArea = None, + z_level: types.Numeric = 0, + z: types.Numeric = 2, tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, + blur_opts: types.Blur = None, + select_opts: types.Select = None, + encode: types.Union[types.JSFunc, dict, None] = None, ): - self._append_legend(series_name, is_selected) + if box_width is None: + box_width = [7, 50] + + self._append_legend(series_name) self.options.get("series").append( { - "type": ChartType.BOXPLOT, + "type": chart_type, "name": series_name, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, "xAxisIndex": xaxis_index, + "xAxisId": xaxis_id, "yAxisIndex": yaxis_index, + "yAxisId": yaxis_id, + "datasetIndex": dataset_index, + "colorBy": color_by, + "legendHoverLink": is_legend_hover_link, + "hoverAnimation": is_hover_animation, + "layout": layout, + "boxWidth": box_width, + "selectedMode": selected_mode, + "dimensions": dimensions, "data": y_axis, "label": label_opts, "markPoint": markpoint_opts, "markLine": markline_opts, + "markArea": markarea_opts, + "zlevel": z_level, + "z": z, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, + "blur": blur_opts, + "select": select_opts, + "encode": encode, } ) return self @@ -48,6 +93,8 @@ def add_yaxis( def prepare_data(items): data = [] for item in items: + if not item: + data.append([]) try: d, res = sorted(item), [] for i in range(1, 4): @@ -63,6 +110,7 @@ def prepare_data(items): elif m == 3 / 4: res.append(d[k - 1] * 0.25 + d[k] * 0.75) data.append([d[0]] + res + [d[-1]]) - except Exception: - pass + except TypeError: + # one of the item element is None + data.append([]) return data diff --git a/pyecharts/charts/basic_charts/calendar.py b/pyecharts/charts/basic_charts/calendar.py index eff3d7b54..ed565b87c 100644 --- a/pyecharts/charts/basic_charts/calendar.py +++ b/pyecharts/charts/basic_charts/calendar.py @@ -1,6 +1,7 @@ from ... import options as opts from ... import types from ...charts.chart import Chart +from ...globals import ChartType class Calendar(Chart): @@ -12,34 +13,50 @@ class Calendar(Chart): Two categories of axes must be used in rectangular coordinates. """ - def __init__(self, init_opts: types.Init = opts.InitOpts()): - super().__init__(init_opts=init_opts) - self.options.update(calendar=opts.CalendarOpts().opts) + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) def add( self, series_name: str, yaxis_data: types.Sequence, *, - is_selected: bool = True, - label_opts: types.Label = opts.LabelOpts(), - calendar_opts: types.Calendar = None, + type_: types.Union[str, ChartType] = ChartType.HEATMAP, + calendar_index: types.Optional[types.Numeric] = None, + label_opts: types.Label = opts.LabelOpts(is_show=False, position="inside"), + calendar_opts: types.Union[types.Calendar, types.List[types.Calendar]] = None, tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + visualmap_opts: types.VisualMap = None, + emphasis_opts: types.Emphasis = None, + **other_calendar_opts, ): if calendar_opts: - self.options.update(calendar=calendar_opts) + if self.options.get("calendar"): + self.options.get("calendar").append(calendar_opts) + else: + self.options.update(calendar=[calendar_opts]) + + if visualmap_opts: + self.options.update(visualMap=visualmap_opts) - self._append_legend(series_name, is_selected) + self._append_legend(series_name) self.options.get("series").append( { - "type": "heatmap", + "type": type_, "coordinateSystem": "calendar", + "calendarIndex": calendar_index, "name": series_name, "data": yaxis_data, "label": label_opts, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, + **other_calendar_opts, } ) return self diff --git a/pyecharts/charts/basic_charts/chord.py b/pyecharts/charts/basic_charts/chord.py new file mode 100644 index 000000000..bd45997d0 --- /dev/null +++ b/pyecharts/charts/basic_charts/chord.py @@ -0,0 +1,74 @@ +from ... import types +from ...charts.chart import Chart +from ...globals import ChartType + + +class Chord(Chart): + """ + <<< Chord >>> + + The chord diagram visually presents the flow and weights + within complex relationship networks, making it particularly + suitable for multidimensional relationship analysis in scenarios + such as financial transactions and social networks. + """ + + def add( + self, + series_name: str, + data: types.Sequence[types.ChordData], + links: types.Sequence[types.ChordLink], + *, + is_clockwise: bool = False, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + color_by: types.Optional[str] = None, + pos_left: types.Optional[str] = None, + pos_top: types.Optional[str] = None, + pos_right: types.Optional[str] = None, + pos_bottom: types.Optional[str] = None, + width: types.Optional[str] = None, + height: types.Optional[str] = None, + center: types.Optional[types.Sequence] = None, + radius: types.Optional[types.Union[types.Sequence, str]] = None, + start_angle: types.Numeric = 90, + end_angle: types.Optional[types.Numeric] = None, + min_angle: types.Optional[types.Numeric] = None, + pad_angle: types.Optional[types.Numeric] = None, + tooltip_opts: types.Tooltip = None, + label_opts: types.Label = None, + linestyle_opts: types.LineStyle = None, + itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, + ): + self.options.get("series").append({ + "type": ChartType.CHORD, + "name": series_name, + "data": data, + "links": links, + "clockwise": is_clockwise, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "colorBy": color_by, + "left": pos_left, + "top": pos_top, + "right": pos_right, + "bottom": pos_bottom, + "width": width, + "height": height, + "center": center, + "radius": radius, + "startAngle": start_angle, + "endAngle": end_angle, + "minAngle": min_angle, + "padAngle": pad_angle, + "tooltip": tooltip_opts, + "label": label_opts, + "lineStyle": linestyle_opts, + "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, + }) + + return self diff --git a/pyecharts/charts/basic_charts/custom.py b/pyecharts/charts/basic_charts/custom.py new file mode 100644 index 000000000..6978a41f7 --- /dev/null +++ b/pyecharts/charts/basic_charts/custom.py @@ -0,0 +1,139 @@ +from ... import options as opts +from ... import types +from ...charts.chart import Chart +from ...globals import ChartType + + +class Custom(Chart): + """ + <<< Custom >>> + + Custom series allows you to customize the rendering of graphical elements + in the series. This enables the extension of different charts. + """ + + def register_echarts_x(self, chart_type: str): + if chart_type not in [ + ChartType.VIOLIN, + ChartType.STAGE, + ChartType.DOUGHNUT, + ChartType.CONTOUR, + ChartType.BAR_RANGE, + ChartType.LINE_RANGE, + ]: + raise ValueError(f"Not support register this chart type: {chart_type}") + + if chart_type == ChartType.VIOLIN: + self.js_dependencies.add("echarts-x-violin") + self.options.update(xAxis=[{}], yAxis=[{}]) + + if chart_type == ChartType.STAGE: + self.js_dependencies.add("echarts-x-stage") + self.options.update(xAxis=[{}], yAxis=[{}]) + + if chart_type == ChartType.DOUGHNUT: + self.js_dependencies.add("echarts-x-segmented-doughnut") + + if chart_type == ChartType.LINE_RANGE: + self.js_dependencies.add("echarts-x-line-range") + self.options.update(xAxis=[{}], yAxis=[{}]) + + if chart_type == ChartType.CONTOUR: + self.js_dependencies.add("echarts-x-contour-d3") + self.js_dependencies.add("echarts-x-contour") + self.options.update(xAxis=[{}], yAxis=[{}]) + + if chart_type == ChartType.BAR_RANGE: + self.js_dependencies.add("echarts-x-bar-range") + self.options.update(xAxis=[{}], yAxis=[{}]) + + return self + + def add_xaxis(self, xaxis_data: types.Sequence): + self.options["xAxis"][0].update(data=xaxis_data) + self._xaxis_data = xaxis_data + return self + + def add( + self, + series_name: str, + render_item: types.JSFunc, + *, + type_: str = ChartType.CUSTOM, + color_by: str = "series", + is_legend_hover_link: bool = True, + coordinate_system: str = "cartesian2d", + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + x_axis_index: types.Numeric = 0, + xaxis_id: types.Optional[types.Numeric] = None, + y_axis_index: types.Numeric = 0, + yaxis_id: types.Optional[types.Numeric] = None, + polar_index: types.Numeric = 0, + polar_id: types.Optional[types.Numeric] = None, + single_axis_index: types.Optional[types.Numeric] = None, + single_axis_id: types.Optional[types.Numeric] = None, + geo_index: types.Numeric = 0, + geo_id: types.Optional[types.Numeric] = None, + calendar_index: types.Numeric = 0, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, + dataset_index: types.Numeric = 0, + series_layout_by: str = "column", + selected_mode: types.Union[bool, str] = False, + dimensions: types.Optional[types.Sequence] = None, + encode: types.Union[types.Sequence, dict, None] = None, + data: types.Optional[types.Sequence] = None, + is_clip: bool = True, + z_level: types.Numeric = 0, + z: types.Numeric = 2, + itemstyle_opts: types.ItemStyle = None, + tooltip_opts: types.Tooltip = None, + label_opts: types.Label = None, + emphasis_opts: types.Emphasis = None, + item_payload_opts: types.CustomItemPayload = None, + ): + self._append_legend(series_name) + + self.options.get("series").append( + { + "type": type_, + "name": series_name, + "renderItem": render_item, + "colorBy": color_by, + "legendHoverLink": is_legend_hover_link, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "xAxisIndex": x_axis_index, + "xAxisId": xaxis_id, + "yAxisIndex": y_axis_index, + "yAxisId": yaxis_id, + "polarIndex": polar_index, + "polarId": polar_id, + "singleAxisIndex": single_axis_index, + "singleAxisId": single_axis_id, + "geoIndex": geo_index, + "geoId": geo_id, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, + "datasetIndex": dataset_index, + "seriesLayoutBy": series_layout_by, + "itemStyle": itemstyle_opts, + "selectedMode": selected_mode, + "dimensions": dimensions, + "encode": encode, + "data": data, + "clip": is_clip, + "zlevel": z_level, + "z": z, + "tooltip": tooltip_opts, + "label": label_opts, + "emphasis": emphasis_opts, + "itemPayload": item_payload_opts, + } + ) + return self diff --git a/pyecharts/charts/basic_charts/effectscatter.py b/pyecharts/charts/basic_charts/effectscatter.py index fe8534fdc..5b57901aa 100644 --- a/pyecharts/charts/basic_charts/effectscatter.py +++ b/pyecharts/charts/basic_charts/effectscatter.py @@ -16,20 +16,44 @@ def add_yaxis( series_name: str, y_axis: types.Sequence[types.Union[opts.EffectScatterItem, dict]], *, - is_selected: bool = True, xaxis_index: types.Optional[types.Numeric] = None, + xaxis_id: types.Optional[types.Numeric] = None, yaxis_index: types.Optional[types.Numeric] = None, + yaxis_id: types.Optional[types.Numeric] = None, + polar_index: types.Optional[types.Numeric] = None, + polar_id: types.Optional[types.Numeric] = None, + geo_index: types.Optional[types.Numeric] = None, + geo_id: types.Optional[types.Numeric] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, + dataset_index: types.Optional[types.Numeric] = None, color: types.Optional[str] = None, + color_by: types.Optional[str] = None, + is_legend_hover_link: bool = True, + show_effect_on: str = "render", + coordinate_system: str = "cartesian2d", + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, symbol: types.Optional[str] = None, symbol_size: types.Numeric = 10, symbol_rotate: types.Optional[types.Numeric] = None, + selected_mode: types.Union[bool, str] = False, label_opts: types.Label = opts.LabelOpts(), effect_opts: types.Effect = opts.EffectOpts(), tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, + markpoint_opts: types.MarkPoint = None, + markline_opts: types.MarkLine = None, + markarea_opts: types.MarkArea = None, + z_level: types.Numeric = 0, + z: types.Numeric = 2, + encode: types.Union[types.JSFunc, dict, None] = None, ): self._append_color(color) - self._append_legend(series_name, is_selected) + self._append_legend(series_name) if all([isinstance(d, opts.EffectScatterItem) for d in y_axis]): y_axis = y_axis @@ -41,16 +65,40 @@ def add_yaxis( "type": ChartType.EFFECT_SCATTER, "name": series_name, "xAxisIndex": xaxis_index, + "xAxisId": xaxis_id, "yAxisIndex": yaxis_index, - "showEffectOn": "render", + "yAxisId": yaxis_id, + "polarIndex": polar_index, + "polarId": polar_id, + "geoIndex": geo_index, + "geoId": geo_id, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, + "colorBy": color_by, + "legendHoverLink": is_legend_hover_link, + "showEffectOn": show_effect_on, "rippleEffect": effect_opts, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "datasetIndex": dataset_index, "symbol": symbol, "symbolSize": symbol_size, "symbolRotate": symbol_rotate, + "selectedMode": selected_mode, "data": y_axis, "label": label_opts, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, + "markPoint": markpoint_opts, + "markLine": markline_opts, + "markArea": markarea_opts, + "zlevel": z_level, + "z": z, + "encode": encode, } ) return self diff --git a/pyecharts/charts/basic_charts/funnel.py b/pyecharts/charts/basic_charts/funnel.py index af191012d..454cc2259 100644 --- a/pyecharts/charts/basic_charts/funnel.py +++ b/pyecharts/charts/basic_charts/funnel.py @@ -20,23 +20,52 @@ def add( series_name: str, data_pair: types.Sequence, *, - is_selected: bool = True, color: types.Optional[str] = None, + color_by: types.Optional[str] = None, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, + min_: types.Numeric = 0, + max_: types.Numeric = 100, + min_size: types.Union[str, types.Numeric] = "0%", + max_size: types.Union[str, types.Numeric] = "100%", + orient: str = "vertical", sort_: str = "descending", gap: types.Numeric = 0, + is_legend_hover_link: bool = True, + funnel_align: str = "center", label_opts: types.Label = opts.LabelOpts(), tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, + selected_mode: types.Union[bool, str] = False, + z_level: types.Numeric = 0, + z: types.Numeric = 2, + pos_top: types.Union[str, types.Numeric, None] = None, + pos_left: types.Union[str, types.Numeric, None] = None, + pos_bottom: types.Union[str, types.Numeric, None] = None, + pos_right: types.Union[str, types.Numeric, None] = None, + width: types.Union[str, types.Numeric, None] = None, + height: types.Union[str, types.Numeric, None] = None, + dataset_index: types.Optional[types.Numeric] = None, + encode: types.Union[types.JSFunc, dict, None] = None, + markpoint_opts: types.MarkPoint = None, + markline_opts: types.MarkLine = None, + markarea_opts: types.MarkArea = None, ): self._append_color(color) if all([isinstance(d, opts.FunnelItem) for d in data_pair]): data = data_pair for a in data_pair: - self._append_legend(a.opts.get("name"), is_selected) + self._append_legend(a.opts.get("name")) else: data = [{"name": n, "value": v} for n, v in data_pair] for a, _ in data_pair: - self._append_legend(a, is_selected) + self._append_legend(a) _dset = set(self.options.get("legend")[0].get("data")) self.options.get("legend")[0].update(data=list(_dset)) @@ -46,11 +75,41 @@ def add( "type": ChartType.FUNNEL, "name": series_name, "data": data, + "colorBy": color_by, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, + "min": min_, + "max": max_, + "minSize": min_size, + "maxSize": max_size, + "orient": orient, "sort": sort_, "gap": gap, + "legendHoverLink": is_legend_hover_link, + "funnelAlign": funnel_align, "label": label_opts, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, + "selectedMode": selected_mode, + "zlevel": z_level, + "z": z, + "left": pos_left, + "right": pos_right, + "top": pos_top, + "bottom": pos_bottom, + "width": width, + "height": height, + "datasetIndex": dataset_index, + "encode": encode, + "markPoint": markpoint_opts, + "markLine": markline_opts, + "markArea": markarea_opts, } ) return self diff --git a/pyecharts/charts/basic_charts/gauge.py b/pyecharts/charts/basic_charts/gauge.py index ab80597a7..581aa1141 100644 --- a/pyecharts/charts/basic_charts/gauge.py +++ b/pyecharts/charts/basic_charts/gauge.py @@ -16,25 +16,42 @@ def add( series_name: str, data_pair: types.Sequence, *, - is_selected: bool = True, min_: types.Numeric = 0, max_: types.Numeric = 100, split_number: types.Numeric = 10, + center: types.Sequence = None, radius: types.Union[types.Numeric, str] = "75%", + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, start_angle: types.Numeric = 225, end_angle: types.Numeric = -45, is_clock_wise: bool = True, - title_label_opts: types.GaugeTitle = opts.GaugeTitleOpts(), + title_label_opts: types.GaugeTitle = opts.GaugeTitleOpts( + offset_center=["0%", "20%"], + ), detail_label_opts: types.GaugeDetail = opts.GaugeDetailOpts( - formatter="{value}%" + formatter="{value}%", + offset_center=["0%", "40%"], ), + progress: types.GaugeProgress = opts.GaugeProgressOpts(), pointer: types.GaugePointer = opts.GaugePointerOpts(), + anchor: types.GaugeAnchor = opts.GaugeAnchorOpts(), tooltip_opts: types.Tooltip = None, axisline_opts: types.AxisLine = None, + axistick_opts: types.AxisTick = None, + axislabel_opts: types.AxisLabel = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, ): + if center is None: + center = ["50%", "50%"] - self._append_legend(series_name, is_selected) + self._append_legend(series_name) self.options.get("series").append( { "type": ChartType.GAUGE, @@ -44,15 +61,28 @@ def add( "min": min_, "max": max_, "splitNumber": split_number, + "center": center, "radius": radius, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, "startAngle": start_angle, "endAngle": end_angle, "clockwise": is_clock_wise, "data": [{"name": n, "value": v} for n, v in data_pair], "tooltip": tooltip_opts, "axisLine": axisline_opts, + "axisTick": axistick_opts, + "axisLabel": axislabel_opts, + "progress": progress, + "anchor": anchor, "pointer": pointer, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, } ) return self diff --git a/pyecharts/charts/basic_charts/geo.py b/pyecharts/charts/basic_charts/geo.py index 0b956b3e4..2f84e92a5 100644 --- a/pyecharts/charts/basic_charts/geo.py +++ b/pyecharts/charts/basic_charts/geo.py @@ -9,14 +9,22 @@ class GeoChartBase(Chart): - def __init__(self, init_opts: types.Init = opts.InitOpts()): - super().__init__(init_opts=init_opts) + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) self.set_global_opts() self._coordinates = COORDINATES self._zlevel = 1 self._coordinate_system: types.Optional[str] = None self._chart_type = ChartType.GEO + def add_geo_json(self, geo_json: dict): + self._geo_json = geo_json + return self + def add_coordinate( self, name: str, longitude: types.Numeric, latitude: types.Numeric ): @@ -40,18 +48,18 @@ def add( data_pair: types.Sequence, type_: str = "scatter", *, - is_selected: bool = True, symbol: types.Optional[str] = None, symbol_size: types.Numeric = 12, blur_size: types.Numeric = 20, point_size: types.Numeric = 20, + radius: types.Optional[types.Sequence] = None, color: types.Optional[str] = None, is_polyline: bool = False, is_large: bool = False, large_threshold: types.Numeric = 2000, progressive: types.Numeric = 400, progressive_threshold: types.Numeric = 3000, - label_opts: types.Label = opts.LabelOpts(), + label_opts: types.Label = None, effect_opts: types.Effect = opts.EffectOpts(), linestyle_opts: types.LineStyle = opts.LineStyleOpts(), tooltip_opts: types.Tooltip = None, @@ -60,10 +68,10 @@ def add( encode: types.Union[types.JsCode, dict] = None, ): self._zlevel += 1 - data = self._feed_data(data_pair, type_) + data = self._feed_data(data_pair, type_) if data_pair else data_pair self._append_color(color) - self._append_legend(series_name, is_selected) + self._append_legend(series_name) if type_ == ChartType.SCATTER: self.options.get("series").append( @@ -79,7 +87,19 @@ def add( "itemStyle": itemstyle_opts, } ) - + elif type_ == ChartType.SCATTERGL: + self.js_dependencies.add("echarts-gl") + self.options.get("series").append( + { + "type": type_, + "name": series_name, + "coordinateSystem": self._coordinate_system, + "symbol": symbol, + "symbolSize": symbol_size, + "data": data, + "itemStyle": itemstyle_opts, + } + ) elif type_ == ChartType.EFFECT_SCATTER: self.options.get("series").append( { @@ -96,7 +116,17 @@ def add( "itemStyle": itemstyle_opts, } ) - + elif type_ == ChartType.FLOWGL: + self.js_dependencies.add("echarts-gl") + self.options.get("series").append( + { + "type": type_, + "name": series_name, + "coordinateSystem": self._coordinate_system, + "data": data, + "itemStyle": itemstyle_opts, + } + ) elif type_ == ChartType.HEATMAP: self.options.get("series").append( { @@ -110,7 +140,6 @@ def add( "blurSize": blur_size, } ) - elif type_ == ChartType.LINES: self.options.get("series").append( { @@ -133,6 +162,19 @@ def add( "label": label_opts, } ) + elif type_ == ChartType.LINESGL: + self.js_dependencies.add("echarts-gl") + self.options.get("series").append( + { + "type": type_, + "name": series_name, + "coordinateSystem": self._coordinate_system, + "data": data, + "polyline": is_polyline, + "large": is_large, + "lineStyle": linestyle_opts, + } + ) elif type_ == ChartType.CUSTOM: self.options.get("series").append( { @@ -145,6 +187,33 @@ def add( "data": data, } ) + elif type_ == ChartType.PIE: + if not radius: + radius = ["0%", "5%"] + + if not tooltip_opts: + tooltip_opts = {"formatter": "{b}: {c} ({d}%)"} + + if not isinstance(data[0], opts.PieItem): + data = [{"name": n, "value": v} for n, v in data] + + self.options.get("series").append( + { + "type": type_, + "coordinateSystem": self._coordinate_system, + "data": data, + "tooltip": tooltip_opts, + "label": label_opts, + "center": self.get_coordinate(series_name), + "radius": radius, + } + ) + # Legend (hard code here) + legend = self.options.get("legend")[0] + pie_series_name = [d.get("name") for d in data] + if len(legend.get("data")) < len(pie_series_name): + legend["data"] = pie_series_name + return self @@ -159,13 +228,30 @@ def __init__( self, init_opts: types.Init = opts.InitOpts(), is_ignore_nonexistent_coord: bool = False, + render_opts: types.RenderInit = opts.RenderOpts(), ): - super().__init__(init_opts=init_opts) + super().__init__(init_opts=init_opts, render_opts=render_opts) self._coordinate_system: types.Optional[str] = "geo" self._is_ignore_nonexistent_coord = is_ignore_nonexistent_coord def _feed_data(self, data_pair: types.Sequence, type_: str) -> types.Sequence: + if type_ == ChartType.PIE: + return data_pair + result = [] + if isinstance(data_pair[0], opts.GeoItem): + for item in data_pair: + result.append({ + "name": item.get("name"), + "value": [ + item.get("longitude"), + item.get("latitude"), + item.get("value"), + ], + }) + + return result + for n, v in data_pair: try: if type_ == ChartType.LINES: @@ -182,7 +268,9 @@ def _feed_data(self, data_pair: types.Sequence, type_: str) -> types.Sequence: def add_schema( self, maptype: str = "china", + animation: types.Union[bool, str] = None, is_roam: bool = True, + roam_trigger: types.Optional[str] = None, zoom: types.Optional[types.Numeric] = None, center: types.Optional[types.Sequence] = None, aspect_scale: types.Numeric = 0.75, @@ -197,8 +285,27 @@ def add_schema( itemstyle_opts: types.ItemStyle = None, emphasis_itemstyle_opts: types.ItemStyle = None, emphasis_label_opts: types.Label = None, + regions_opts: types.Union[ + types.Sequence[types.GeoRegions], types.Sequence[dict] + ] = None, + is_preserve_aspect: bool = False, + preserve_aspect_align: types.Optional[str] = None, + preserve_aspect_vertical_align: types.Optional[str] = None, + is_clip: bool = False, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Optional[types.Union[ + types.Sequence, types.Numeric, str] + ] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, + tooltip_opts: types.Tooltip = None, + select_opts: types.Select = None, ): self.js_dependencies.add(maptype) + self._geo_json_name = maptype if center: assert len(center) == 2 @@ -212,9 +319,11 @@ def add_schema( self.options.update( geo={ "map": maptype, + "animation": animation, "zoom": zoom, "center": center, "roam": is_roam, + "roamTrigger": roam_trigger, "aspectScale": aspect_scale, "boundingCoords": bounding_coords, "scaleLimit": scale_limit, @@ -228,6 +337,20 @@ def add_schema( "itemStyle": emphasis_itemstyle_opts, "label": emphasis_label_opts, }, + "regions": regions_opts, + "preserveAspect": is_preserve_aspect, + "preserveAspectAlign": preserve_aspect_align, + "preserveAspectVerticalAlign": preserve_aspect_vertical_align, + "clip": is_clip, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, + "tooltip": tooltip_opts, + "select": select_opts, } ) return self diff --git a/pyecharts/charts/basic_charts/gmap.py b/pyecharts/charts/basic_charts/gmap.py new file mode 100644 index 000000000..1f42de106 --- /dev/null +++ b/pyecharts/charts/basic_charts/gmap.py @@ -0,0 +1,77 @@ +from ... import options as opts +from ... import types +from ...charts.basic_charts.geo import GeoChartBase +from ...commons.utils import OrderedSet, JsCode +from ...exceptions import NonexistentCoordinatesException +from ...globals import ChartType + +GMAP_API = "https://maps.googleapis.com/maps/api/js?key={}" + + +class GMap(GeoChartBase): + """ + <<< GMap(Google Map) coordinate system >>> + + Support scatter plot, line. + """ + + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + is_ignore_nonexistent_coord: bool = False, + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) + self.js_dependencies.add("gmap") + self._is_geo_chart = True + self._coordinate_system: types.Optional[str] = "gmap" + self.gmap_js_functions: OrderedSet = OrderedSet() + self._is_ignore_nonexistent_coord = is_ignore_nonexistent_coord + + def _feed_data(self, data_pair: types.Sequence, type_: str) -> types.Sequence: + result = [] + type_list = [ChartType.LINES, ChartType.CUSTOM] + if type_ in type_list: + result = data_pair + else: + for n, v in data_pair: + try: + lng, lat = self.get_coordinate(n) + result.append({"name": n, "value": [lng, lat, v]}) + except TypeError as err: + if self._is_ignore_nonexistent_coord is not True: + raise NonexistentCoordinatesException(err, (n, v)) + return result + + def add_schema( + self, + gmap_ak: str, + center: types.Sequence, + zoom: types.Union[types.Numeric, str] = None, + is_render_on_map: bool = True, + z_index: types.Optional[int] = None, + is_roam: bool = True, + ): + self.js_dependencies.add(GMAP_API.format(gmap_ak)) + self.options.update( + gmap={ + "center": center, + "zoom": zoom, + "renderOnMoving": is_render_on_map, + "echartsLayerZIndex": z_index, + "roam": is_roam + } + ) + return self + + def add_control_panel( + self, + is_add_traffic_layer: bool = False, + ): + if is_add_traffic_layer: + self.gmap_js_functions.add( + "var trafficLayer = new google.maps.TrafficLayer(); " + "trafficLayer.setMap(gmap);" + ) + + return self diff --git a/pyecharts/charts/basic_charts/graph.py b/pyecharts/charts/basic_charts/graph.py index 1c6e31f97..03bf375fc 100644 --- a/pyecharts/charts/basic_charts/graph.py +++ b/pyecharts/charts/basic_charts/graph.py @@ -18,16 +18,36 @@ def add( links: types.Sequence[types.GraphLink], categories: types.Union[types.Sequence[types.GraphCategory], None] = None, *, - is_selected: bool = True, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + xaxis_index: types.Optional[types.Numeric] = None, + xaxis_id: types.Optional[types.Numeric] = None, + yaxis_index: types.Optional[types.Numeric] = None, + yaxis_id: types.Optional[types.Numeric] = None, + polar_index: types.Optional[types.Numeric] = None, + polar_id: types.Optional[types.Numeric] = None, + single_axis_index: types.Optional[types.Numeric] = None, + single_axis_id: types.Optional[types.Numeric] = None, + geo_index: types.Optional[types.Numeric] = None, + geo_id: types.Optional[types.Numeric] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, is_focusnode: bool = True, is_roam: bool = True, + roam_trigger: types.Optional[str] = None, + node_scale_ratio: types.Numeric = 0.6, is_draggable: bool = False, is_rotate_label: bool = False, layout: str = "force", symbol: types.Optional[str] = None, symbol_size: types.Numeric = 10, - edge_length: types.Numeric = 50, + edge_length: types.Numeric = 30, gravity: types.Numeric = 0.2, + friction: types.Numeric = 0.6, + is_layout_animation: bool = True, repulsion: types.Numeric = 50, edge_label: types.Label = None, edge_symbol: types.Union[types.Sequence[str], str] = None, @@ -36,6 +56,10 @@ def add( linestyle_opts: types.LineStyle = opts.LineStyleOpts(), tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, + is_preserve_aspect: bool = False, + preserve_aspect_align: types.Optional[str] = None, + preserve_aspect_vertical_align: types.Optional[str] = None, ): _nodes = [] for n in nodes: @@ -53,7 +77,7 @@ def add( for c in categories: if isinstance(c, opts.GraphCategory): c = c.opts - self._append_legend(c.get("name", ""), is_selected) + self._append_legend(c.get("name", "")) if edge_label is None: edge_label = opts.LabelOpts(is_show=False) @@ -65,18 +89,39 @@ def add( { "type": ChartType.GRAPH, "name": series_name, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "xaxisIndex": xaxis_index, + "xaxisId": xaxis_id, + "yaxisIndex": yaxis_index, + "yaxisId": yaxis_id, + "polarIndex": polar_index, + "polarId": polar_id, + "singleAxisIndex": single_axis_index, + "singleAxisId": single_axis_id, + "geoIndex": geo_index, + "geoId": geo_id, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, "layout": layout, "symbol": symbol, "symbolSize": symbol_size, "circular": {"rotateLabel": is_rotate_label}, "force": { "repulsion": repulsion, - "edgeLength": edge_length, "gravity": gravity, + "edgeLength": edge_length, + "friction": friction, + "layoutAnimation": is_layout_animation, }, "label": label_opts, "lineStyle": linestyle_opts, "roam": is_roam, + "roamTrigger": roam_trigger, + "nodeScaleRatio": node_scale_ratio, "draggable": is_draggable, "focusNodeAdjacency": is_focusnode, "data": _nodes, @@ -87,6 +132,10 @@ def add( "links": _links, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, + "preserveAspect": is_preserve_aspect, + "preserveAspectAlign": preserve_aspect_align, + "preserveAspectVerticalAlign": preserve_aspect_vertical_align, } ) return self diff --git a/pyecharts/charts/basic_charts/heatmap.py b/pyecharts/charts/basic_charts/heatmap.py index 9d12f399a..2b47fb42f 100644 --- a/pyecharts/charts/basic_charts/heatmap.py +++ b/pyecharts/charts/basic_charts/heatmap.py @@ -13,8 +13,12 @@ class HeatMap(RectChart): Two categories of axes must be used in rectangular coordinates. """ - def __init__(self, init_opts: types.Init = opts.InitOpts()): - super().__init__(init_opts=init_opts) + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) self.set_global_opts(visualmap_opts=opts.VisualMapOpts(orient="horizontal")) def add_yaxis( @@ -23,29 +27,72 @@ def add_yaxis( yaxis_data: types.Sequence[types.Union[dict]], value: types.Sequence[types.Union[dict]], *, - is_selected: bool = True, + coordinate_system: str = "cartesian2d", + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, xaxis_index: types.Optional[types.Numeric] = None, + xaxis_id: types.Optional[types.Numeric] = None, yaxis_index: types.Optional[types.Numeric] = None, + yaxis_id: types.Optional[types.Numeric] = None, + geo_index: types.Optional[types.Numeric] = None, + geo_id: types.Optional[types.Numeric] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, + dataset_index: types.Optional[types.Numeric] = None, + point_size: types.Optional[types.Numeric] = None, + blur_size: types.Optional[types.Numeric] = None, + min_opacity: types.Optional[types.Numeric] = None, + max_opacity: types.Optional[types.Numeric] = None, label_opts: types.Label = opts.LabelOpts(), markpoint_opts: types.MarkPoint = None, markline_opts: types.MarkLine = None, + markarea_opts: types.MarkArea = None, tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, + selected_mode: types.Union[bool, str] = False, + z_level: types.Numeric = 0, + z: types.Numeric = 2, + encode: types.Union[types.JSFunc, dict, None] = None, ): - self._append_legend(series_name, is_selected) + self._append_legend(series_name) self.options.get("yAxis")[0].update(data=yaxis_data) self.options.get("series").append( { "type": ChartType.HEATMAP, "name": series_name, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, "xAxisIndex": xaxis_index, + "xAxisId": xaxis_id, "yAxisIndex": yaxis_index, + "yAxisId": yaxis_id, + "geoIndex": geo_index, + "geoId": geo_id, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, + "datasetIndex": dataset_index, + "pointSize": point_size, + "blurSize": blur_size, + "minOpacity": min_opacity, + "maxOpacity": max_opacity, "data": value, "label": label_opts, "markLine": markline_opts, "markPoint": markpoint_opts, + "markArea": markarea_opts, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, + "selectedMode": selected_mode, + "zlevel": z_level, + "z": z, + "encode": encode, } ) return self diff --git a/pyecharts/charts/basic_charts/kline.py b/pyecharts/charts/basic_charts/kline.py index dd3471548..d89dd6146 100644 --- a/pyecharts/charts/basic_charts/kline.py +++ b/pyecharts/charts/basic_charts/kline.py @@ -14,8 +14,12 @@ class Kline(RectChart): the fluctuation of a certain period. """ - def __init__(self, init_opts: types.Init = opts.InitOpts()): - super().__init__(init_opts=init_opts) + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) self.set_global_opts( xaxis_opts=opts.AxisOpts(is_scale=True), yaxis_opts=opts.AxisOpts(is_scale=True), @@ -26,26 +30,65 @@ def add_yaxis( series_name: str, y_axis: types.Sequence[types.Union[opts.CandleStickItem, dict]], *, - is_selected: bool = True, + coordinate_system: str = "cartesian2d", + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + color_by: types.Optional[str] = "series", + bar_width: types.Optional[types.Numeric] = None, + bar_min_width: types.Optional[types.Numeric] = None, + bar_max_width: types.Optional[types.Numeric] = None, + layout: types.Optional[str] = None, xaxis_index: types.Optional[types.Numeric] = None, + xaxis_id: types.Optional[types.Numeric] = None, yaxis_index: types.Optional[types.Numeric] = None, + yaxis_id: types.Optional[types.Numeric] = None, + is_legend_hover_link: bool = True, + is_hover_animation: bool = True, markline_opts: types.MarkLine = None, markpoint_opts: types.MarkPoint = None, + markarea_opts: types.MarkArea = None, tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, + selected_mode: types.Union[bool, str] = False, + is_large: bool = False, + encode: types.Union[types.JSFunc, dict, None] = None, + is_clip: bool = True, + z_level: types.Numeric = 0, + z: types.Numeric = 2, ): - self._append_legend(series_name, is_selected) + self._append_legend(series_name) self.options.get("series").append( { "type": ChartType.KLINE, "name": series_name, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "colorBy": color_by, + "legendHoverLink": is_legend_hover_link, + "hoverAnimation": is_hover_animation, + "layout": layout, + "barWidth": bar_width, + "barMinWidth": bar_min_width, + "barMaxWidth": bar_max_width, "xAxisIndex": xaxis_index, + "xAxisId": xaxis_id, "yAxisIndex": yaxis_index, + "yAxisId": yaxis_id, "data": y_axis, "markPoint": markpoint_opts, "markLine": markline_opts, + "markArea": markarea_opts, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, + "selectedMode": selected_mode, + "large": is_large, + "encode": encode, + "clip": is_clip, + "zlevel": z_level, + "z": z, } ) return self diff --git a/pyecharts/charts/basic_charts/line.py b/pyecharts/charts/basic_charts/line.py index 011b1b15b..2613d6681 100644 --- a/pyecharts/charts/basic_charts/line.py +++ b/pyecharts/charts/basic_charts/line.py @@ -17,38 +17,66 @@ def add_yaxis( series_name: str, y_axis: types.Sequence[types.Union[opts.LineItem, dict]], *, - is_selected: bool = True, is_connect_nones: bool = False, xaxis_index: types.Optional[types.Numeric] = None, + xaxis_id: types.Optional[types.Numeric] = None, yaxis_index: types.Optional[types.Numeric] = None, + yaxis_id: types.Optional[types.Numeric] = None, + polar_index: types.Optional[types.Numeric] = None, + polar_id: types.Optional[types.Numeric] = None, + dataset_index: types.Optional[types.Numeric] = None, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + color_by: types.Optional[str] = None, color: types.Optional[str] = None, is_symbol_show: bool = True, symbol: types.Optional[str] = None, symbol_size: types.Union[types.Numeric, types.Sequence] = 4, stack: types.Optional[str] = None, + stack_strategy: types.Optional[str] = "samesign", + stack_order: types.Optional[str] = None, is_smooth: bool = False, is_clip: bool = True, is_step: bool = False, is_hover_animation: bool = True, z_level: types.Numeric = 0, z: types.Numeric = 0, + log_base: types.Numeric = 10, + sampling: types.Optional[str] = None, + dimensions: types.Union[types.Sequence, None] = None, + series_layout_by: str = "column", markpoint_opts: types.MarkPoint = None, markline_opts: types.MarkLine = None, + markarea_opts: types.MarkArea = None, tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, label_opts: types.Label = opts.LabelOpts(), + end_label_opts: types.Label = None, linestyle_opts: types.LineStyle = opts.LineStyleOpts(), areastyle_opts: types.AreaStyle = opts.AreaStyleOpts(), + emphasis_opts: types.Emphasis = None, + encode: types.Union[types.JSFunc, dict, None] = None, ): self._append_color(color) - self._append_legend(series_name, is_selected) + self._append_legend(series_name) if all([isinstance(d, opts.LineItem) for d in y_axis]): data = y_axis else: # 合并 x 和 y 轴数据,避免当 X 轴的类型设置为 'value' 的时候, # X、Y 轴均显示 Y 轴数据 - data = [list(z) for z in zip(self._xaxis_data, y_axis)] + try: + xaxis_index = xaxis_index or 0 + data = [ + list(z) + for z in zip(self.options["xAxis"][xaxis_index]["data"], y_axis) + ] + except IndexError: + data = [list(z) for z in zip(self._xaxis_data, y_axis)] + + if self.options.get("dataset") is not None and not y_axis: + data = None self.options.get("series").append( { @@ -56,7 +84,16 @@ def add_yaxis( "name": series_name, "connectNulls": is_connect_nones, "xAxisIndex": xaxis_index, + "xAxisId": xaxis_id, "yAxisIndex": yaxis_index, + "yAxisId": yaxis_id, + "polarIndex": polar_index, + "polarId": polar_id, + "datasetIndex": dataset_index, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "colorBy": color_by, "symbol": symbol, "symbolSize": symbol_size, "showSymbol": is_symbol_show, @@ -64,13 +101,23 @@ def add_yaxis( "clip": is_clip, "step": is_step, "stack": stack, + "stackStrategy": stack_strategy, + "stackOrder": stack_order, "data": data, "hoverAnimation": is_hover_animation, "label": label_opts, + "endLabel": end_label_opts, + "logBase": log_base, + "sampling": sampling, + "dimensions": dimensions, + "encode": encode, + "seriesLayoutBy": series_layout_by, "lineStyle": linestyle_opts, "areaStyle": areastyle_opts, + "emphasis": emphasis_opts, "markPoint": markpoint_opts, "markLine": markline_opts, + "markArea": markarea_opts, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, "zlevel": z_level, diff --git a/pyecharts/charts/basic_charts/liquid.py b/pyecharts/charts/basic_charts/liquid.py index 2e2a48b1e..8713631f2 100644 --- a/pyecharts/charts/basic_charts/liquid.py +++ b/pyecharts/charts/basic_charts/liquid.py @@ -11,8 +11,12 @@ class Liquid(Chart): The liquid chart is mainly used to highlight the percentage of data. """ - def __init__(self, init_opts: types.Init = opts.InitOpts()): - super().__init__(init_opts=init_opts) + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) self.js_dependencies.add("echarts-liquidfill") def add( diff --git a/pyecharts/charts/basic_charts/lmap.py b/pyecharts/charts/basic_charts/lmap.py new file mode 100644 index 000000000..68a4062e3 --- /dev/null +++ b/pyecharts/charts/basic_charts/lmap.py @@ -0,0 +1,66 @@ +from ... import options as opts +from ... import types +from ...charts.basic_charts.geo import GeoChartBase +from ...commons.utils import OrderedSet, JsCode +from ...exceptions import NonexistentCoordinatesException +from ...globals import ChartType + + +class LMap(GeoChartBase): + """ + <<< LMap(leaflet) coordinate system >>> + + Support scatter plot, line. + """ + + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + is_ignore_nonexistent_coord: bool = False, + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) + self.js_dependencies.add("lmap-css") + self.js_dependencies.add("lmap-src") + self.js_dependencies.add("lmap") + self._is_geo_chart = True + self._coordinate_system: types.Optional[str] = "lmap" + self.lmap_js_functions: OrderedSet = OrderedSet() + self._is_ignore_nonexistent_coord = is_ignore_nonexistent_coord + + def _feed_data(self, data_pair: types.Sequence, type_: str) -> types.Sequence: + result = [] + type_list = [ChartType.LINES, ChartType.CUSTOM] + if type_ in type_list: + result = data_pair + else: + for n, v in data_pair: + try: + lng, lat = self.get_coordinate(n) + result.append({"name": n, "value": [lng, lat, v]}) + except TypeError as err: + if self._is_ignore_nonexistent_coord is not True: + raise NonexistentCoordinatesException(err, (n, v)) + return result + + def add_schema( + self, + center: types.Sequence, + zoom: types.Union[types.Numeric, str] = None, + is_enable_resize: bool = True, + is_render_on_map: bool = True, + is_layer_interactive: bool = True, + is_large: bool = False, + ): + self.options.update( + lmap={ + "center": center, + "zoom": zoom, + "resizeEnable": is_enable_resize, + "renderOnMoving": is_render_on_map, + "echartsLayerInteractive": is_layer_interactive, + "largeMode": is_large, + } + ) + + return self diff --git a/pyecharts/charts/basic_charts/map.py b/pyecharts/charts/basic_charts/map.py index 3fa175f68..678e9ba40 100644 --- a/pyecharts/charts/basic_charts/map.py +++ b/pyecharts/charts/basic_charts/map.py @@ -17,7 +17,6 @@ def add( data_pair: types.Sequence[types.Union[types.Sequence, opts.MapItem, dict]], maptype: str = "china", *, - is_selected: bool = True, is_roam: bool = True, center: types.Optional[types.Sequence] = None, aspect_scale: types.Numeric = 0.75, @@ -31,8 +30,25 @@ def add( symbol: types.Optional[str] = None, map_value_calculation: str = "sum", is_map_symbol_show: bool = True, + z_level: types.Numeric = 0, + z: types.Numeric = 2, + pos_left: types.Optional[types.Union[str, types.Numeric]] = None, + pos_top: types.Optional[types.Union[str, types.Numeric]] = None, + pos_right: types.Optional[types.Union[str, types.Numeric]] = None, + pos_bottom: types.Optional[types.Union[str, types.Numeric]] = None, + geo_index: types.Optional[types.Numeric] = None, + geo_id: types.Optional[types.Numeric] = None, + series_layout_by: str = "column", + dataset_index: types.Optional[types.Numeric] = 0, layout_center: types.Optional[types.Sequence[str]] = None, layout_size: types.Union[str, types.Numeric] = None, + is_preserve_aspect: bool = False, + preserve_aspect_align: types.Optional[str] = None, + preserve_aspect_vertical_align: types.Optional[str] = None, + is_clip: bool = False, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, label_opts: types.Label = opts.LabelOpts(), tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, @@ -40,6 +56,7 @@ def add( emphasis_itemstyle_opts: types.ItemStyle = None, ): self.js_dependencies.add(maptype) + self._geo_json_name = maptype if isinstance(data_pair[0], opts.MapItem): data = data_pair @@ -53,14 +70,14 @@ def add( if min_scale_limit is None and max_scale_limit is None: scale_limit = None - self._append_legend(series_name, is_selected) + self._append_legend(series_name) self.options.get("series").append( { "type": ChartType.MAP, "name": series_name, "symbol": symbol, "label": label_opts, - "mapType": maptype, + "map": maptype, "data": data, "roam": is_roam, "aspectScale": aspect_scale, @@ -71,10 +88,27 @@ def add( "center": center, "zoom": zoom, "nameMap": name_map, + "zlevel": z_level, + "z": z, + "left": pos_left, + "top": pos_top, + "right": pos_right, + "bottom": pos_bottom, + "geoIndex": geo_index, + "geoId": geo_id, + "seriesLayoutBy": series_layout_by, + "datasetIndex": dataset_index, "mapValueCalculation": map_value_calculation, "showLegendSymbol": is_map_symbol_show, "layoutCenter": layout_center, "layoutSize": layout_size, + "preserveAspect": is_preserve_aspect, + "preserveAspectAlign": preserve_aspect_align, + "preserveAspectVerticalAlign": preserve_aspect_vertical_align, + "clip": is_clip, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, "emphasis": { @@ -87,4 +121,6 @@ def add( class Map(Chart, MapMixin): - pass + def add_geo_json(self, geo_json: dict): + self._geo_json = geo_json + return self diff --git a/pyecharts/charts/basic_charts/parallel.py b/pyecharts/charts/basic_charts/parallel.py index 8a2f73119..3138ad106 100644 --- a/pyecharts/charts/basic_charts/parallel.py +++ b/pyecharts/charts/basic_charts/parallel.py @@ -12,8 +12,12 @@ class Parallel(Chart): high dimensional data. """ - def __init__(self, init_opts: types.Init = opts.InitOpts()): - super().__init__(init_opts=init_opts) + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) self.options.update(parallel=opts.ParallelOpts().opts) def add_schema( @@ -37,25 +41,47 @@ def add_schema( def add( self, series_name: str, - data: types.Sequence[types.Union[dict]], + data: types.Sequence[types.Union[opts.ParallelItem, dict]], *, + coordinate_system: types.Optional[str] = "parallel", + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + parallel_index: types.Optional[types.Numeric] = None, + parallel_id: types.Optional[types.Numeric] = None, + color_by: types.Optional[str] = None, + inactive_opacity: types.Optional[types.Numeric] = 0.05, + active_opacity: types.Optional[types.Numeric] = 1, + is_realtime: bool = True, is_smooth: bool = False, - is_selected: bool = True, + z_level: types.Numeric = 0, + z: types.Numeric = 2, linestyle_opts: types.LineStyle = opts.LineStyleOpts(), tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, ): - self._append_legend(series_name, is_selected) + self._append_legend(series_name) self.options.get("series").append( { "type": ChartType.PARALLEL, - "coordinateSystem": "parallel", + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "parallelIndex": parallel_index, + "parallelId": parallel_id, + "colorBy": color_by, + "inactiveOpacity": inactive_opacity, + "activeOpacity": active_opacity, + "realTime": is_realtime, + "zlevel": z_level, + "z": z, "lineStyle": linestyle_opts, "name": series_name, "data": data, "smooth": is_smooth, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, } ) return self diff --git a/pyecharts/charts/basic_charts/pictorialbar.py b/pyecharts/charts/basic_charts/pictorialbar.py index 84fcbe02b..94c221d65 100644 --- a/pyecharts/charts/basic_charts/pictorialbar.py +++ b/pyecharts/charts/basic_charts/pictorialbar.py @@ -26,9 +26,13 @@ def add_yaxis( symbol_repeat_direction: types.Optional[str] = None, symbol_margin: types.Union[types.Numeric, str, None] = None, is_symbol_clip: bool = False, - is_selected: bool = True, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, xaxis_index: types.Optional[types.Numeric] = None, + xaxis_id: types.Optional[types.Numeric] = None, yaxis_index: types.Optional[types.Numeric] = None, + yaxis_id: types.Optional[types.Numeric] = None, color: types.Optional[str] = None, category_gap: types.Union[types.Numeric, str] = "20%", gap: types.Optional[str] = None, @@ -38,9 +42,10 @@ def add_yaxis( tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, encode: types.Union[types.JsCode, dict] = None, + emphasis_opts: types.Emphasis = None, ): self._append_color(color) - self._append_legend(series_name, is_selected) + self._append_legend(series_name) self.options.get("series").append( { "type": ChartType.PICTORIALBAR, @@ -54,8 +59,13 @@ def add_yaxis( "symbolMargin": symbol_margin, "symbolClip": is_symbol_clip, "name": series_name, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, "xAxisIndex": xaxis_index, + "xAxisId": xaxis_id, "yAxisIndex": yaxis_index, + "yAxisId": yaxis_id, "data": y_axis, "barCategoryGap": category_gap, "barGap": gap, @@ -65,6 +75,7 @@ def add_yaxis( "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, "encode": encode, + "emphasis": emphasis_opts, } ) return self diff --git a/pyecharts/charts/basic_charts/pie.py b/pyecharts/charts/basic_charts/pie.py index e6de03f64..87dd561b0 100644 --- a/pyecharts/charts/basic_charts/pie.py +++ b/pyecharts/charts/basic_charts/pie.py @@ -19,20 +19,46 @@ def add( data_pair: types.Sequence[types.Union[types.Sequence, opts.PieItem, dict]], *, color: types.Optional[str] = None, + color_by: types.Optional[str] = "data", + is_legend_hover_link: bool = True, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + geo_index: types.Optional[types.Numeric] = None, + geo_id: types.Optional[types.Numeric] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, + selected_mode: types.Union[str, bool] = False, + selected_offset: types.Numeric = 10, radius: types.Optional[types.Sequence] = None, center: types.Optional[types.Sequence] = None, - rosetype: types.Optional[str] = None, + rosetype: types.Union[str, bool] = None, is_clockwise: bool = True, + start_angle: types.Numeric = 90, + end_angle: types.Optional[types.Numeric] = None, + min_angle: types.Numeric = 0, + min_show_label_angle: types.Numeric = 0, + is_avoid_label_overlap: bool = True, + is_still_show_zero_sum: bool = True, + percent_precision: types.Numeric = 2, + is_show_empty_circle: bool = True, + empty_circle_style_opts: types.PieEmptyCircle = opts.PieEmptyCircleStyle(), label_opts: types.Label = opts.LabelOpts(), - label_line_opts: types.PieLabelLine = None, + label_line_opts: types.PieLabelLine = opts.PieLabelLineOpts(), tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, encode: types.Union[types.JSFunc, dict, None] = None, + markpoint_opts: types.MarkPoint = None, + markline_opts: types.MarkLine = None, + markarea_opts: types.MarkArea = None, ): if self.options.get("dataset") is not None: data = None self.options.get("legend")[0].update( - data=[d[0] for d in self.options.get("dataset").get("source")][1:] + data=[d[0] for d in self.options.get("dataset")[0].get("source")][1:] ) elif isinstance(data_pair[0], opts.PieItem): data = data_pair @@ -57,7 +83,29 @@ def add( { "type": ChartType.PIE, "name": series_name, + "colorBy": color_by, + "legendHoverLink": is_legend_hover_link, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "geoIndex": geo_index, + "geoId": geo_id, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, + "selectedMode": selected_mode, + "selectedOffset": selected_offset, "clockwise": is_clockwise, + "startAngle": start_angle, + "endAngle": end_angle, + "minAngle": min_angle, + "minShowLabelAngle": min_show_label_angle, + "avoidLabelOverlap": is_avoid_label_overlap, + "stillShowZeroSum": is_still_show_zero_sum, + "percentPrecision": percent_precision, + "showEmptyCircle": is_show_empty_circle, + "emptyCircleStyle": empty_circle_style_opts, "data": data, "radius": radius, "center": center, @@ -66,7 +114,11 @@ def add( "labelLine": label_line_opts, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, "encode": encode, + "markPoint": markpoint_opts, + "markLine": markline_opts, + "markArea": markarea_opts, } ) return self diff --git a/pyecharts/charts/basic_charts/polar.py b/pyecharts/charts/basic_charts/polar.py index ec56fbfb8..c0b34185c 100644 --- a/pyecharts/charts/basic_charts/polar.py +++ b/pyecharts/charts/basic_charts/polar.py @@ -12,8 +12,12 @@ class Polar(Chart): Polar coordinates can be used for scatter and polyline graphs. """ - def __init__(self, init_opts: types.Init = opts.InitOpts()): - super().__init__(init_opts=init_opts) + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) self.add_schema() def add_schema( @@ -33,20 +37,43 @@ def add( series_name: str, data: types.Sequence, *, - is_selected: bool = True, type_: str = "line", symbol: types.Optional[str] = None, symbol_size: types.Numeric = 4, stack: types.Optional[str] = None, + center: types.Optional[types.Sequence] = None, + z_level: types.Numeric = 0, + z: types.Numeric = 2, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, label_opts: types.Label = opts.LabelOpts(is_show=False), areastyle_opts: types.AreaStyle = opts.AreaStyleOpts(), effect_opts: types.Effect = opts.EffectOpts(), tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, ): - self._append_legend(series_name, is_selected) - self.options.update(polar={}) + self._append_legend(series_name) + self.options.update(polar={ + "center": center if center else ["50%", "50%"], + "zlevel": z_level, + "z": z, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, + "tooltip": tooltip_opts, + }) + # polar with other series config if type_ in (ChartType.SCATTER, ChartType.LINE, ChartType.BAR): self.options.get("series").append( { @@ -61,6 +88,7 @@ def add( "areaStyle": areastyle_opts, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, } ) @@ -78,6 +106,7 @@ def add( "label": label_opts, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, } ) diff --git a/pyecharts/charts/basic_charts/radar.py b/pyecharts/charts/basic_charts/radar.py index e687fa1aa..8bd3ca772 100644 --- a/pyecharts/charts/basic_charts/radar.py +++ b/pyecharts/charts/basic_charts/radar.py @@ -17,17 +17,30 @@ def add_schema( shape: types.Optional[str] = None, center: types.Optional[types.Sequence] = None, radius: types.Optional[types.Union[types.Sequence, str]] = None, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, + start_angle: types.Numeric = 90, textstyle_opts: types.TextStyle = opts.TextStyleOpts(), splitline_opt: types.SplitLine = opts.SplitLineOpts(is_show=True), splitarea_opt: types.SplitArea = opts.SplitAreaOpts(), axisline_opt: types.AxisLine = opts.AxisLineOpts(), + axistick_opt: types.AxisTick = None, + minor_tick_opts: types.MinorTick = None, + axislabel_opt: types.Label = None, + axispointer_opt: types.AxisPointer = None, radiusaxis_opts: types.RadiusAxis = None, angleaxis_opts: types.AngleAxis = None, polar_opts: types.Polar = None, ): - self.options.update( - radiusAxis=radiusaxis_opts, angleAxis=angleaxis_opts, polar=polar_opts + radiusAxis=radiusaxis_opts, + angleAxis=angleaxis_opts, + polar=polar_opts, ) indicators = [] @@ -36,16 +49,31 @@ def add_schema( s = s.opts indicators.append(s) - self.options.update( - radar={ + if self.options.get("radar") is None: + self.options.update(radar=[]) + + self.options.get("radar").append( + { "indicator": indicators, "shape": shape, "center": center, "radius": radius, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, + "startAngle": start_angle, "name": {"textStyle": textstyle_opts}, "splitLine": splitline_opt, "splitArea": splitarea_opt, "axisLine": axisline_opt, + "axisTick": axistick_opt, + "minorTick": minor_tick_opts, + "axisLabel": axislabel_opt, + "axisPointer": axispointer_opt, } ) return self @@ -55,30 +83,41 @@ def add( series_name: str, data: types.Sequence[types.Union[opts.RadarItem, dict]], *, - is_selected: bool = True, + color_by: types.Optional[str] = None, symbol: types.Optional[str] = None, color: types.Optional[str] = None, label_opts: opts.LabelOpts = opts.LabelOpts(), + radar_index: types.Numeric = None, + selected_mode: types.Union[bool, str] = False, + z_level: types.Numeric = 0, + z: types.Numeric = 2, linestyle_opts: opts.LineStyleOpts = opts.LineStyleOpts(), areastyle_opts: opts.AreaStyleOpts = opts.AreaStyleOpts(), tooltip_opts: types.Tooltip = None, + emphasis_opts: types.Emphasis = None, ): if all([isinstance(d, opts.RadarItem) for d in data]): for a in data: - self._append_legend(a.get("name"), is_selected) + self._append_legend(a.get("name")) else: - self._append_legend(series_name, is_selected) + self._append_legend(series_name) self.options.get("series").append( { "type": ChartType.RADAR, "name": series_name, "data": data, + "colorBy": color_by, "symbol": symbol, "label": label_opts, + "radarIndex": radar_index, + "selectedMode": selected_mode, + "zlevel": z_level, + "z": z, "itemStyle": {"normal": {"color": color}}, "lineStyle": linestyle_opts, "areaStyle": areastyle_opts, "tooltip": tooltip_opts, + "emphasis": emphasis_opts, } ) return self diff --git a/pyecharts/charts/basic_charts/sankey.py b/pyecharts/charts/basic_charts/sankey.py index 03edf80ea..e0c8f628c 100644 --- a/pyecharts/charts/basic_charts/sankey.py +++ b/pyecharts/charts/basic_charts/sankey.py @@ -19,28 +19,38 @@ def add( nodes: types.Sequence, links: types.Sequence, *, - is_selected: bool = True, pos_left: types.Union[str, types.Numeric] = "5%", pos_top: types.Union[str, types.Numeric] = "5%", pos_right: types.Union[str, types.Numeric] = "20%", pos_bottom: types.Union[str, types.Numeric] = "5%", + width: types.Union[str, types.Numeric] = None, + height: types.Union[str, types.Numeric] = None, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, node_width: types.Numeric = 20, node_gap: types.Numeric = 8, node_align: str = "justify", - layout_iterations: types.Numeric = 32, + layout_iterations: types.Optional[types.Numeric] = None, orient: str = "horizontal", is_draggable: bool = True, - focus_node_adjacency: types.Union[bool, str] = False, + center: types.Optional[types.Sequence] = None, + zoom: types.Numeric = 1, + is_roam: bool = False, + roam_trigger: types.Optional[str] = None, + edge_label_opt: types.Label = None, levels: types.SankeyLevel = None, label_opts: types.Label = opts.LabelOpts(), linestyle_opt: types.LineStyle = opts.LineStyleOpts(), tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, ): - if layout_iterations < 32: - layout_iterations = 32 - - self._append_legend(series_name, is_selected) + self._append_legend(series_name) self.options.get("series").append( { "type": ChartType.SANKEY, @@ -51,18 +61,32 @@ def add( "top": pos_top, "right": pos_right, "bottom": pos_bottom, + "width": width, + "height": height, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, "nodeWidth": node_width, "nodeGap": node_gap, "nodeAlign": node_align, - "layoutIteration": layout_iterations, + "layoutIterations": layout_iterations, "orient": orient, "draggable": is_draggable, - "focusNodeAdjacency": focus_node_adjacency, + "center": center, + "zoom": zoom, + "roam": is_roam, + "roamTrigger": roam_trigger, + "edgeLabel": edge_label_opt, "levels": levels, "label": label_opts, "lineStyle": linestyle_opt, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, } ) return self diff --git a/pyecharts/charts/basic_charts/scatter.py b/pyecharts/charts/basic_charts/scatter.py index d028b5d6f..7ac26f591 100644 --- a/pyecharts/charts/basic_charts/scatter.py +++ b/pyecharts/charts/basic_charts/scatter.py @@ -38,23 +38,40 @@ def add_yaxis( series_name: str, y_axis: types.Sequence[types.Union[opts.ScatterItem, dict]], *, - is_selected: bool = True, + color_by: types.Optional[str] = None, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, xaxis_index: types.Optional[types.Numeric] = None, + xaxis_id: types.Optional[types.Numeric] = None, yaxis_index: types.Optional[types.Numeric] = None, + yaxis_id: types.Optional[types.Numeric] = None, + polar_index: types.Optional[types.Numeric] = None, + polar_id: types.Optional[types.Numeric] = None, + single_axis_index: types.Optional[types.Numeric] = None, + single_axis_id: types.Optional[types.Numeric] = None, + geo_index: types.Optional[types.Numeric] = None, + geo_id: types.Optional[types.Numeric] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, color: types.Optional[str] = None, symbol: types.Optional[str] = None, symbol_size: types.Union[types.Numeric, types.Sequence] = 10, symbol_rotate: types.Optional[types.Numeric] = None, label_opts: types.Label = opts.LabelOpts(position="right"), + is_silent: bool = False, markpoint_opts: types.MarkPoint = None, markline_opts: types.MarkLine = None, markarea_opts: types.MarkArea = None, tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, encode: types.Union[types.JSFunc, dict, None] = None, ): self._append_color(color) - self._append_legend(series_name, is_selected) + self._append_legend(series_name) data = self._parse_data(y_axis=y_axis) @@ -62,18 +79,36 @@ def add_yaxis( { "type": ChartType.SCATTER, "name": series_name, + "colorBy": color_by, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, "xAxisIndex": xaxis_index, + "xAxisId": xaxis_id, "yAxisIndex": yaxis_index, + "yAxisId": yaxis_id, + "polarIndex": polar_index, + "polarId": polar_id, + "singleAxisIndex": single_axis_index, + "singleAxisId": single_axis_id, + "geoIndex": geo_index, + "geoId": geo_id, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, "symbol": symbol, "symbolSize": symbol_size, "symbolRotate": symbol_rotate, "data": data, "label": label_opts, + "silent": is_silent, "markPoint": markpoint_opts, "markLine": markline_opts, "markArea": markarea_opts, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, "encode": encode, } ) diff --git a/pyecharts/charts/basic_charts/sunburst.py b/pyecharts/charts/basic_charts/sunburst.py index cb16b9f72..15ad5c5d0 100644 --- a/pyecharts/charts/basic_charts/sunburst.py +++ b/pyecharts/charts/basic_charts/sunburst.py @@ -21,12 +21,26 @@ def add( *, center: types.Optional[types.Sequence] = None, radius: types.Optional[types.Sequence] = None, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, highlight_policy: str = "descendant", node_click: str = "rootToNode", sort_: types.Optional[types.JSFunc] = "desc", - levels: types.Optional[types.Sequence] = None, + is_render_label_for_zero_data: bool = False, + is_clockwise: bool = True, + start_angle: types.Numeric = 90, + levels: types.Optional[types.Sequence[types.SunburstLevelOpts]] = None, label_opts: types.Label = opts.LabelOpts(), + label_line_opts: types.SunburstLabelLine = None, + label_layout_opts: types.SunburstLabelLayout = None, itemstyle_opts: types.ItemStyle = None, + tooltip_opts: types.Tooltip = None, + emphasis_opts: types.Emphasis = None, ): if not center: center = ["50%", "50%"] @@ -40,12 +54,26 @@ def add( "data": data_pair, "center": center, "radius": radius, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, "highlightPolicy": highlight_policy, "nodeClick": node_click, "sort": sort_, + "renderLabelForZeroData": is_render_label_for_zero_data, + "clockwise": is_clockwise, + "startAngle": start_angle, "levels": levels, "label": label_opts, + "labelLine": label_line_opts, + "labelLayout": label_layout_opts, "itemStyle": itemstyle_opts, + "tooltip": tooltip_opts, + "emphasis": emphasis_opts, } ) return self diff --git a/pyecharts/charts/basic_charts/themeriver.py b/pyecharts/charts/basic_charts/themeriver.py index 7692ef68e..b5ae258da 100644 --- a/pyecharts/charts/basic_charts/themeriver.py +++ b/pyecharts/charts/basic_charts/themeriver.py @@ -18,23 +18,50 @@ def add( series_name: types.Sequence, data: types.Sequence[types.Union[opts.ThemeRiverItem, dict]], *, - is_selected: bool = True, + color_by: types.Optional[str] = None, + pos_left: types.Union[str, types.Numeric] = "5%", + pos_top: types.Union[str, types.Numeric] = "5%", + pos_right: types.Union[str, types.Numeric] = "5%", + pos_bottom: types.Union[str, types.Numeric] = "5%", + width: types.Union[str, types.Numeric] = None, + height: types.Union[str, types.Numeric] = None, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + single_axis_index: types.Optional[types.Numeric] = None, + single_axis_id: types.Optional[types.Numeric] = None, + boundary_gap: types.Optional[types.Sequence] = None, label_opts: types.Label = opts.LabelOpts(), singleaxis_opts: types.SingleAxis = opts.SingleAxisOpts(), tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, ): for n in series_name: - self._append_legend(n, is_selected) + self._append_legend(n) self.options.get("series").append( { "type": ChartType.THEMERIVER, "name": series_name, "data": data, + "colorBy": color_by, + "left": pos_left, + "top": pos_top, + "right": pos_right, + "bottom": pos_bottom, + "width": width, + "height": height, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "singleAxisIndex": single_axis_index, + "singleAxisId": single_axis_id, + "boundaryGap": boundary_gap, "label": label_opts, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, } ) diff --git a/pyecharts/charts/basic_charts/tree.py b/pyecharts/charts/basic_charts/tree.py index 02a1d55d7..34c006618 100644 --- a/pyecharts/charts/basic_charts/tree.py +++ b/pyecharts/charts/basic_charts/tree.py @@ -37,24 +37,40 @@ def add( series_name: str, data: types.Sequence[types.Union[opts.TreeItem, dict]], *, + zoom: types.Optional[types.Numeric] = 1, layout: str = "orthogonal", symbol: types.JSFunc = "emptyCircle", symbol_size: types.Union[types.JSFunc, types.Numeric, types.Sequence] = 7, orient: str = "LR", - pos_top: types.Optional[str] = None, - pos_left: types.Optional[str] = None, - pos_bottom: types.Optional[str] = None, - pos_right: types.Optional[str] = None, + pos_top: types.Union[str, types.Numeric, None] = None, + pos_left: types.Union[str, types.Numeric, None] = None, + pos_bottom: types.Union[str, types.Numeric, None] = None, + pos_right: types.Union[str, types.Numeric, None] = None, + width: types.Union[str, types.Numeric, None] = None, + height: types.Union[str, types.Numeric, None] = None, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, + center: types.Optional[types.Sequence[types.Union[str, types.Numeric]]] = None, collapse_interval: types.Numeric = 0, edge_shape: str = "curve", edge_fork_position: str = "50%", is_roam: bool = False, + roam_trigger: types.Optional[str] = None, is_expand_and_collapse: bool = True, initial_tree_depth: types.Optional[types.Numeric] = None, label_opts: types.Label = opts.LabelOpts(), - leaves_label_opts: types.Label = opts.LabelOpts(), + leaves_opts: types.TreeLeavesOpts = opts.TreeLeavesOpts(), tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, + emphasis_opts: types.Emphasis = None, + selected_mode: types.Union[bool, str] = False, + blur_opts: types.Blur = None, + select_opts: types.Select = None, ): _data = self._set_collapse_interval(data, collapse_interval) self.options.get("series").append( @@ -66,19 +82,35 @@ def add( "right": pos_right, "top": pos_top, "bottom": pos_bottom, + "width": width, + "height": height, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, + "center": center, + "zoom": zoom, "symbol": symbol, "symbolSize": symbol_size, "edgeShape": edge_shape, "edgeForkPosition": edge_fork_position, "roam": is_roam, + "roamTrigger": roam_trigger, "expandAndCollapse": is_expand_and_collapse, "initialTreeDepth": initial_tree_depth, "layout": layout, "orient": orient, "label": label_opts, - "leaves": {"label": leaves_label_opts}, + "leaves": leaves_opts, "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, + "selectedMode": selected_mode, + "blur": blur_opts, + "select": select_opts, } ) return self diff --git a/pyecharts/charts/basic_charts/treemap.py b/pyecharts/charts/basic_charts/treemap.py index b47f84da6..27395d5af 100644 --- a/pyecharts/charts/basic_charts/treemap.py +++ b/pyecharts/charts/basic_charts/treemap.py @@ -17,7 +17,6 @@ def add( series_name: str, data: types.Sequence[types.Union[opts.TreeItem, dict]], *, - is_selected: bool = True, leaf_depth: types.Optional[types.Numeric] = None, pos_left: types.Optional[str] = None, pos_right: types.Optional[str] = None, @@ -25,6 +24,13 @@ def add( pos_bottom: types.Optional[str] = None, width: types.Union[str, types.Numeric] = "80%", height: types.Union[str, types.Numeric] = "80%", + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Union[types.Sequence, types.Numeric, str] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, square_ratio: types.Optional[types.JSFunc] = None, drilldown_icon: str = "▶", roam: types.Union[bool, str] = True, @@ -33,6 +39,7 @@ def add( levels: types.TreeMapLevel = None, visual_min: types.Optional[types.Numeric] = None, visual_max: types.Optional[types.Numeric] = None, + visual_dimension: types.Optional[types.Numeric] = None, color_alpha: types.Union[types.Numeric, types.Sequence] = None, color_saturation: types.Union[types.Numeric, types.Sequence] = None, color_mapping_by: str = "index", @@ -43,8 +50,9 @@ def add( tooltip_opts: types.Tooltip = None, itemstyle_opts: types.ItemStyle = None, breadcrumb_opts: types.TreeMapBreadcrumb = None, + emphasis_opts: types.Emphasis = None, ): - self._append_legend(series_name, is_selected) + self._append_legend(series_name) self.options.get("series").append( { "type": ChartType.TREEMAP, @@ -55,10 +63,17 @@ def add( "top": pos_top, "width": width, "height": height, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, "bottom": pos_bottom, "squareRatio": square_ratio, "label": label_opts, - "upperlabel": upper_label_opts, + "upperLabel": upper_label_opts, "leafDepth": leaf_depth, "drillDownIcon": drilldown_icon, "roam": roam, @@ -67,6 +82,7 @@ def add( "levels": levels, "visualMin": visual_min, "visualMax": visual_max, + "visualDimension": visual_dimension, "colorAlpha": color_alpha, "colorSaturation": color_saturation, "colorMappingBy": color_mapping_by, @@ -75,6 +91,7 @@ def add( "tooltip": tooltip_opts, "itemStyle": itemstyle_opts, "breadcrumb": breadcrumb_opts, + "emphasis": emphasis_opts, } ) return self diff --git a/pyecharts/charts/basic_charts/wordcloud.py b/pyecharts/charts/basic_charts/wordcloud.py index 098427796..60dcd94d4 100644 --- a/pyecharts/charts/basic_charts/wordcloud.py +++ b/pyecharts/charts/basic_charts/wordcloud.py @@ -31,8 +31,12 @@ class WordCloud(Chart): appear frequently in the text. """ - def __init__(self, init_opts: types.Init = opts.InitOpts()): - super().__init__(init_opts=init_opts) + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) self.js_dependencies.add("echarts-wordcloud") self._mask_image_suffix: types.Sequence = ["jpg", "jpeg", "png", "ico"] @@ -89,9 +93,7 @@ def add( ): data = [] for n, v in data_pair: - data.append( - {"name": n, "value": v, "textStyle": {"normal": {"color": gen_color()}}} - ) + data.append({"name": n, "value": v, "textStyle": {"color": gen_color()}}) word_size_range = word_size_range or (12, 60) diff --git a/pyecharts/charts/chart.py b/pyecharts/charts/chart.py index fb156a677..f83071601 100644 --- a/pyecharts/charts/chart.py +++ b/pyecharts/charts/chart.py @@ -6,19 +6,16 @@ class Chart(Base): - def __init__(self, init_opts: types.Init = opts.InitOpts()): + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + render_opts: types.RenderInit = opts.RenderOpts(), + ): if isinstance(init_opts, dict): temp_opts = opts.InitOpts() temp_opts.update(**init_opts) init_opts = temp_opts - super().__init__(init_opts=init_opts) - self.colors = ( - "#c23531 #2f4554 #61a0a8 #d48265 #749f83 #ca8622 #bda29a #6e7074 " - "#546570 #c4ccd3 #f05b72 #ef5b9c #f47920 #905a3d #fab27b #2a5caa " - "#444693 #726930 #b2d235 #6d8346 #ac6767 #1d953f #6950a1 #918597" - ).split() - if init_opts.opts.get("theme") == ThemeType.WHITE: - self.options.update(color=self.colors) + super().__init__(init_opts=init_opts, render_opts=render_opts) self.options.update( series=[], legend=[{"data": [], "selected": dict()}], @@ -26,6 +23,25 @@ def __init__(self, init_opts: types.Init = opts.InitOpts()): ) self._chart_type: Optional[str] = None + def set_dark_mode( + self, + dark_mode_colors: Optional[Sequence[str]] = None, + dark_mode_bg_color: str = "#100C2A", + ): + # [Hard Code Here] The Echarts default Dark Mode Configurations + if dark_mode_colors is None: + dark_mode_colors = ( + "#4992ff #7cffb2 #fddd60 #ff6e76 #58d9f9 #05c091 #ff8a45 " + "#8d48e3 #dd79ff" + ).split() + self.options.update( + backgroundColor=dark_mode_bg_color, + darkMode=True, + color=dark_mode_colors, + ) + self.theme = ThemeType.DARK + return self + def set_colors(self, colors: Sequence[str]): self.options.update(color=colors) return self @@ -84,15 +100,15 @@ def set_series_opts( return self - def _append_legend(self, name, is_selected): + def _append_legend(self, name): self.options.get("legend")[0].get("data").append(name) - self.options.get("legend")[0].get("selected").update({name: is_selected}) def _append_color(self, color: Optional[str]): if color: - self.colors = [color] + self.colors - if self.theme == ThemeType.WHITE: - self.options.update(color=self.colors) + if self.options.get("color"): + self.options.get("color").append(color) + else: + self.options.update(color=[color]) def set_global_opts( self, @@ -107,11 +123,14 @@ def set_global_opts( datazoom_opts: types.DataZoom = None, graphic_opts: types.Graphic = None, axispointer_opts: types.AxisPointer = None, + matrix_opts: types.Matrix = None, + thumbnail_opts: types.Thumbnail = None, ): if tooltip_opts is None: tooltip_opts = opts.TooltipOpts( formatter=ToolTipFormatterType.get(self._chart_type, None) ) + self.options.update( title=title_opts, toolbox=toolbox_opts, @@ -120,6 +139,8 @@ def set_global_opts( dataZoom=datazoom_opts, graphic=graphic_opts, axisPointer=axispointer_opts, + matrix=matrix_opts, + thumbnail=thumbnail_opts, ) if brush_opts is not None: @@ -128,7 +149,8 @@ def set_global_opts( if isinstance(legend_opts, opts.LegendOpts): legend_opts = legend_opts.opts for _s in self.options["legend"]: - _s.update(legend_opts) + # _s.update(legend_opts) + _s.update(**{k: v for k, v in legend_opts.items() if v is not None}) if xaxis_opts and self.options.get("xAxis", None): if isinstance(xaxis_opts, opts.AxisOpts): @@ -147,20 +169,47 @@ def add_dataset( source: types.Union[types.Sequence, types.JSFunc] = None, dimensions: types.Optional[types.Sequence] = None, source_header: types.Optional[bool] = None, + transform: types.Optional[Sequence[opts.DatasetTransformOpts]] = None, + from_dataset_index: types.Optional[types.Numeric] = None, + from_dataset_id: types.Optional[types.Numeric] = None, + from_transform_result: types.Optional[types.Numeric] = None, ): - self.options.update( - dataset={ - "source": source, - "dimensions": dimensions, - "sourceHeader": source_header, - } - ) + if self.options.get("dataset") is not None: + self.options.get("dataset").append( + { + "source": source, + "dimensions": dimensions, + "sourceHeader": source_header, + "transform": transform, + "fromDatasetIndex": from_dataset_index, + "fromDatasetId": from_dataset_id, + "fromTransformResult": from_transform_result, + } + ) + else: + self.options.update( + dataset=[ + { + "source": source, + "dimensions": dimensions, + "sourceHeader": source_header, + "transform": transform, + "fromDatasetIndex": from_dataset_index, + "fromDatasetId": from_dataset_id, + "fromTransformResult": from_transform_result, + } + ] + ) return self class RectChart(Chart): - def __init__(self, init_opts: types.Init = opts.InitOpts()): - super().__init__(init_opts=init_opts) + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) self.options.update(xAxis=[opts.AxisOpts().opts], yAxis=[opts.AxisOpts().opts]) def extend_axis( @@ -194,10 +243,19 @@ def overlap(self, chart: Base): self.options.get("legend")[0].get("data").extend( chart.options.get("legend")[0].get("data") ) - self.options.get("legend")[0].get("selected").update( - chart.options.get("legend")[0].get("selected") - ) + if self.options.get("legend")[0].get("selected") is not None: + self.options.get("legend")[0].get("selected").update( + chart.options.get("legend")[0].get("selected") + ) self.options.get("series").extend(chart.options.get("series")) + # to merge colors of chart + chart_colors = chart.options.get("color") + if self.options.get("color") is None: + if chart_colors: + self.options.update(color=chart_colors) + else: + if chart_colors: + self.options.get("color").extend(chart_colors) return self @@ -206,27 +264,97 @@ class Chart3D(Chart): `Chart3D`类是所有 3D 类图表的基类,继承自 `Chart` 类 """ - def __init__(self, init_opts: types.Init = opts.InitOpts()): + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + render_opts: types.RenderInit = opts.RenderOpts(), + ): init_opts.renderer = RenderType.CANVAS - super().__init__(init_opts) + super().__init__(init_opts, render_opts) self.js_dependencies.add("echarts-gl") - self.options.update(visualMap=opts.VisualMapOpts().opts) self._3d_chart_type: Optional[str] = None # 3d chart type,don't use it directly + def add_globe( + self, + is_show: bool = True, + globe_radius: types.Numeric = 100, + globe_outer_radius: types.Numeric = 150, + environment: str = "auto", + base_texture: types.Union[str, types.JsCode, None] = None, + height_texture: types.Union[str, types.JsCode, None] = None, + displacement_texture: types.Union[str, types.JsCode, None] = None, + displacement_scale: types.Numeric = 0, + displacement_quality: str = "medium", + shading: types.Optional[str] = None, + realistic_material_opts: types.Optional[types.Map3DRealisticMaterial] = None, + lambert_material_opts: types.Optional[types.Map3DLambertMaterial] = None, + color_material_opts: types.Optional[types.Map3DColorMaterial] = None, + light_opts: types.Optional[types.Map3DLight] = None, + post_effect_opts: types.Optional[types.Map3DPostEffect] = None, + is_enable_super_sampling: types.Union[str, bool] = "auto", + view_control_opts: types.Optional[types.Map3DViewControl] = None, + layers: types.Optional[types.GlobeLayers] = None, + z_level: types.Numeric = -10, + pos_left: types.Union[str, types.Numeric] = "auto", + pos_top: types.Union[str, types.Numeric] = "auto", + pos_right: types.Union[str, types.Numeric] = "auto", + pos_bottom: types.Union[str, types.Numeric] = "auto", + width: types.Union[str, types.Numeric] = "auto", + height: types.Union[str, types.Numeric] = "auto", + ): + self.options.update( + globe={ + "show": is_show, + "globeRadius": globe_radius, + "globeOuterRadius": globe_outer_radius, + "environment": environment, + "baseTexture": base_texture, + "heightTexture": height_texture, + "displacementTexture": displacement_texture, + "displacementScale": displacement_scale, + "displacementQuality": displacement_quality, + "shading": shading, + "realisticMaterial": realistic_material_opts, + "lambertMaterial": lambert_material_opts, + "colorMaterial": color_material_opts, + "light": light_opts, + "postEffect": post_effect_opts, + "temporalSuperSampling": {"enable": is_enable_super_sampling}, + "viewControl": view_control_opts, + "layers": layers, + "zlevel": z_level, + "left": pos_left, + "top": pos_top, + "right": pos_right, + "bottom": pos_bottom, + "width": width, + "height": height, + } + ) + return self + class ThreeAxisChart(Chart3D): def add( self, series_name: str, data: Sequence, + coordinate_system: Optional[str] = None, shading: Optional[str] = None, itemstyle_opts: types.ItemStyle = None, label_opts: types.Label = opts.LabelOpts(is_show=False), - xaxis3d_opts: types.Axis3D = opts.Axis3DOpts(type_="category"), - yaxis3d_opts: types.Axis3D = opts.Axis3DOpts(type_="category"), - zaxis3d_opts: types.Axis3D = opts.Axis3DOpts(type_="value"), + grid_3d_index: types.Numeric = 0, + xaxis3d_opts: types.Axis3D = opts.Axis3DOpts(type_="value", name="X"), + yaxis3d_opts: types.Axis3D = opts.Axis3DOpts(type_="value", name="Y"), + zaxis3d_opts: types.Axis3D = opts.Axis3DOpts(type_="value", name="Z"), grid3d_opts: types.Grid3D = opts.Grid3DOpts(), encode: types.Union[types.JSFunc, dict, None] = None, + emphasis_opts: types.Optional[types.Emphasis3D] = None, + is_parametric: types.Optional[bool] = None, + is_show_wire_frame: types.Optional[bool] = None, + wire_frame_line_style_opts: types.Optional[opts.LineStyleOpts] = None, + equation: types.Optional[dict] = None, + parametric_equation: types.Optional[dict] = None, ): self.options.get("legend")[0].get("data").append(series_name) self.options.update( @@ -236,15 +364,39 @@ def add( grid3D=grid3d_opts, ) - self.options.get("series").append( - { - "type": self._3d_chart_type, - "name": series_name, - "data": data, - "label": label_opts, - "shading": shading, - "itemStyle": itemstyle_opts, - "encode": encode, - } - ) + if self._3d_chart_type == "surface": + self.options.get("series").append( + { + "type": self._3d_chart_type, + "name": series_name, + "coordinateSystem": coordinate_system, + "data": data, + "label": label_opts, + "shading": shading, + "grid3DIndex": grid_3d_index, + "itemStyle": itemstyle_opts, + "parametric": is_parametric, + "wireframe": { + "show": is_show_wire_frame, + "lineStyle": wire_frame_line_style_opts, + }, + "equation": equation, + "parametricEquation": parametric_equation, + } + ) + else: + self.options.get("series").append( + { + "type": self._3d_chart_type, + "name": series_name, + "coordinateSystem": coordinate_system, + "data": data, + "label": label_opts, + "shading": shading, + "grid3DIndex": grid_3d_index, + "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, + "encode": encode, + } + ) return self diff --git a/pyecharts/charts/composite_charts/grid.py b/pyecharts/charts/composite_charts/grid.py index 97d8738d0..4a220df9c 100644 --- a/pyecharts/charts/composite_charts/grid.py +++ b/pyecharts/charts/composite_charts/grid.py @@ -1,8 +1,10 @@ import copy +from typing import Optional from ... import options as opts from ... import types from ...globals import ThemeType +from ..basic_charts.radar import Radar from ..chart import Base, Chart, RectChart @@ -13,8 +15,12 @@ class Grid(Base): and scatter chart (bubble chart) can be drawn in grid. """ - def __init__(self, init_opts: types.Init = opts.InitOpts()): - super().__init__(init_opts=init_opts) + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) self.options: types.Optional[dict] = None self._axis_index: int = 0 self._grow_grid_index: int = 0 @@ -25,12 +31,11 @@ def add( chart: Chart, grid_opts: types.Union[opts.GridOpts, dict], *, - grid_index: int = 0, + grid_index: Optional[int] = None, is_control_axis_index: bool = False, ): if self.options is None: self.options = copy.deepcopy(chart.options) - self.chart_id = chart.chart_id self.options.update(grid=[], title=[]) if self.theme != ThemeType.WHITE: self.options.update(color=[]) @@ -38,10 +43,42 @@ def add( # Priority Order: Grid > Other Chart self.options.update(backgroundColor=self.bg_color) + # 如果是第一个添加的图表,则初始化 dataZoom 和 visualMap 配置 + self.options.update({"dataZoom": None, "visualMap": None}) + if not is_control_axis_index: for s in self.options.get("series"): s.update(xAxisIndex=self._axis_index, yAxisIndex=self._axis_index) + # visualMap 配置添加 + visual_map = chart.options.get("visualMap") + if visual_map is not None: + if self.options.get("visualMap") is None: + self.options.update( + visualMap=[visual_map] if not isinstance(visual_map, list) + else visual_map + ) + else: + self.options.get("visualMap").extend( + [visual_map] if not isinstance(visual_map, list) + else visual_map + ) + + # dataZoom 配置添加 + data_zoom = chart.options.get("dataZoom") + if data_zoom is not None: + if self.options.get("dataZoom") is None: + self.options.update( + dataZoom=[data_zoom] if not isinstance(data_zoom, list) + else data_zoom + ) + else: + self.options.get("dataZoom").extend( + [data_zoom] if not isinstance(data_zoom, list) + else data_zoom + ) + + # title 配置添加 title = chart.options.get("title", opts.TitleOpts().opts) if isinstance(title, opts.TitleOpts): title = title.opts @@ -57,16 +94,26 @@ def add( self.js_dependencies.add(dep) if chart.options.get("geo") is not None: - self.options.update(geo=chart.options.get("geo")) + _grid_geo_option = self.options.get("geo") + if _grid_geo_option is None or isinstance(_grid_geo_option, dict): + self.options.update(geo=[chart.options.get("geo")]) + else: + _grid_geo_option.append(chart.options.get("geo")) if isinstance(chart, RectChart): - if grid_index == 0: + if grid_index is None: grid_index = self._grow_grid_index - for x in chart.options.get("xAxis"): - x.update(gridIndex=grid_index) - for y in chart.options.get("yAxis"): - y.update(gridIndex=grid_index) + if self._grow_grid_index == 0: + for x in self.options.get("xAxis"): + x.update(gridIndex=grid_index) if x.get("gridIndex") is None else ... + for y in self.options.get("yAxis"): + y.update(gridIndex=grid_index) if y.get("gridIndex") is None else ... + else: + for x in chart.options.get("xAxis"): + x.update(gridIndex=grid_index) if x.get("gridIndex") is None else ... + for y in chart.options.get("yAxis"): + y.update(gridIndex=grid_index) if y.get("gridIndex") is None else ... self._grow_grid_index += 1 if self._axis_index > 0: @@ -75,6 +122,8 @@ def add( if isinstance(chart, RectChart): self.options.get("xAxis").extend(chart.options.get("xAxis")) self.options.get("yAxis").extend(chart.options.get("yAxis")) + if isinstance(chart, Radar): + self.options.get("radar").extend(chart.options.get("radar")) self.options.get("grid").append(grid_opts) self._axis_index += 1 diff --git a/pyecharts/charts/composite_charts/page.py b/pyecharts/charts/composite_charts/page.py index e870462d5..65e18a354 100644 --- a/pyecharts/charts/composite_charts/page.py +++ b/pyecharts/charts/composite_charts/page.py @@ -54,17 +54,25 @@ def __init__( page_title: str = CurrentConfig.PAGE_TITLE, js_host: str = "", interval: int = 1, + is_remove_br: bool = False, + is_embed_js: bool = False, + page_border_color: str = "", layout: types.Union[PageLayoutOpts, dict] = PageLayoutOpts(), ): self.js_host: str = js_host or CurrentConfig.ONLINE_HOST self.page_title = page_title self.page_interval = interval + self.remove_br = is_remove_br + self.page_border_color = page_border_color self.layout = self._assembly_layout(layout) self.js_functions: utils.OrderedSet = utils.OrderedSet() self.js_dependencies = utils.OrderedSet() self.download_button: bool = False self._charts: list = [] + self.render_options: dict = {"embed_js": is_embed_js} + self._render_cache: dict = dict() + def add(self, *charts): for c in charts: self._charts.append(c) @@ -124,6 +132,12 @@ def _prepare_render(self): self.css_libs = [self.js_host + link for link in ("jquery-ui.css",)] self.layout = "" + self._render_cache.clear() + if self.render_options.get("embed_js"): + self._render_cache[ + "javascript" + ] = self.load_javascript().load_javascript_contents() + def render( self, path: str = "render.html", diff --git a/pyecharts/charts/composite_charts/tab.py b/pyecharts/charts/composite_charts/tab.py index d6b5064a0..789c27dc4 100644 --- a/pyecharts/charts/composite_charts/tab.py +++ b/pyecharts/charts/composite_charts/tab.py @@ -5,15 +5,67 @@ from ... import types from ...commons import utils from ...globals import CurrentConfig, ThemeType +from ...options.charts_options import TabChartGlobalOpts from ...render import engine from ..mixins import CompositeMixin +DEFAULT_TAB_CSS: str = """ +.chart-container { + display: block; +} + +.chart-container:nth-child(n+2) { + display: none; +} + +.tab { + overflow: hidden; + border: 1px solid #ccc; + background-color: #f1f1f1; +} + +""" +DEFAULT_TAB_BUTTON_CSS: str = """ +.tab button { + background-color: inherit; + float: left; + border: none; + outline: none; + cursor: pointer; + padding: 12px 16px; + transition: 0.3s; +} + +""" +DEFAULT_TAB_BUTTON_HOVER_CSS: str = """ +.tab button:hover { + background-color: #ddd; +} + +""" +DEFAULT_TAB_BUTTON_ACTIVE_CSS: str = """ +.tab button.active { + background-color: #ccc; +} + +""" + + class Tab(CompositeMixin): - def __init__(self, page_title: str = CurrentConfig.PAGE_TITLE, js_host: str = ""): + def __init__( + self, + page_title: str = CurrentConfig.PAGE_TITLE, + js_host: str = "", + bg_color: str = "", + tab_css_opts: TabChartGlobalOpts = TabChartGlobalOpts(), + ): self.js_host: str = js_host or CurrentConfig.ONLINE_HOST self.page_title: str = page_title + self.bg_color = bg_color self.download_button: bool = False + self.use_custom_tab_css = tab_css_opts.opts.get("enable") + self.tab_custom_css = self._prepare_tab_css(css_opts=tab_css_opts) self.js_functions: utils.OrderedSet = utils.OrderedSet() self.js_dependencies: utils.OrderedSet = utils.OrderedSet() self._charts: list = [] @@ -25,8 +77,58 @@ def add(self, chart, tab_name): self.js_dependencies.add(d) return self + def _prepare_tab_css(self, css_opts: TabChartGlobalOpts) -> str: + result = "" + if isinstance(css_opts, TabChartGlobalOpts): + css_opts = css_opts.opts + css_opts = utils.remove_key_with_none_value(css_opts) + + def _dict_to_str(opts: dict, key: str, css_selector: str) -> str: + _inner_result = "" + for k, v in opts.get(key, dict()).items(): + _inner_result += "{}:{}; ".format(k, v) + return ( + f"{css_selector} " + "{ " + _inner_result + " }\n" + if _inner_result != "" + else "" + ) + + # .tab + tab_base = _dict_to_str(opts=css_opts, key="base", css_selector=".tab") + result += tab_base if tab_base != "" else DEFAULT_TAB_CSS + # .tab button + tab_button_base = _dict_to_str( + opts=css_opts, key="button_base", css_selector=".tab button" + ) + result += tab_button_base if tab_button_base != "" else DEFAULT_TAB_BUTTON_CSS + # .tab button:hover + tab_button_hover = _dict_to_str( + opts=css_opts, key="button_hover", css_selector=".tab button:hover" + ) + result += ( + tab_button_hover if tab_button_hover != "" else DEFAULT_TAB_BUTTON_HOVER_CSS + ) + # .tab button.active + tab_button_active = _dict_to_str( + opts=css_opts, key="button_active", css_selector=".tab button.active" + ) + result += ( + tab_button_active + if tab_button_active != "" + else DEFAULT_TAB_BUTTON_ACTIVE_CSS + ) + if ".chart-container" not in result: + result += """ + .chart-container { display: block; } + + .chart-container:nth-child(n+2) { display: none; } + """ + return result + def _prepare_render(self): for c in self: + if not hasattr(c, "_is_tab_chart"): + setattr(c, "_is_tab_chart", True) if hasattr(c, "dump_options"): c.json_contents = c.dump_options() if hasattr(c, "theme"): diff --git a/pyecharts/charts/composite_charts/timeline.py b/pyecharts/charts/composite_charts/timeline.py index d83a93572..648c8d4d1 100644 --- a/pyecharts/charts/composite_charts/timeline.py +++ b/pyecharts/charts/composite_charts/timeline.py @@ -1,3 +1,5 @@ +from typing import Sequence + from ... import options as opts from ... import types from ...charts.chart import Base @@ -8,8 +10,12 @@ class Timeline(Base): `Timeline` provides functions like switching and playing between multiple charts. """ - def __init__(self, init_opts: types.Init = opts.InitOpts()): - super().__init__(init_opts=init_opts) + def __init__( + self, + init_opts: types.Init = opts.InitOpts(), + render_opts: types.RenderInit = opts.RenderOpts(), + ): + super().__init__(init_opts=init_opts, render_opts=render_opts) self.options = {"baseOption": {"series": [], "timeline": {}}, "options": []} self.add_schema() self._time_points: types.Sequence = [] @@ -17,6 +23,7 @@ def __init__(self, init_opts: types.Init = opts.InitOpts()): def add_schema( self, axis_type: str = "category", + current_index: types.Numeric = 0, orient: str = "horizontal", symbol: types.Optional[str] = None, symbol_size: types.Optional[types.Numeric] = None, @@ -33,16 +40,29 @@ def add_schema( pos_bottom: types.Optional[str] = "-5px", width: types.Optional[str] = None, height: types.Optional[str] = None, - linestyle_opts: types.Union[opts.LineStyleOpts, dict, None] = None, - label_opts: types.Optional[opts.LabelOpts] = None, + linestyle_opts: types.LineStyle = None, + label_opts: types.Label = None, itemstyle_opts: types.ItemStyle = None, graphic_opts: types.Graphic = None, checkpointstyle_opts: types.TimeLinkCheckPoint = None, controlstyle_opts: types.TimeLineControl = None, + progress_linestyle_opts: types.LineStyle = None, + progress_itemstyle_opts: types.ItemStyle = None, + progress_label_opts: types.Label = None, + coordinate_system: types.Optional[str] = None, + coordinate_system_usage: types.Optional[str] = None, + coord: types.Optional[types.Union[ + Sequence, types.Numeric, str] + ] = None, + calendar_index: types.Optional[types.Numeric] = None, + calendar_id: types.Optional[types.Numeric] = None, + matrix_index: types.Optional[types.Numeric] = None, + matrix_id: types.Optional[types.Numeric] = None, ): self.options.get("baseOption").get("timeline").update( { "axisType": axis_type, + "currentIndex": current_index, "orient": orient, "autoPlay": is_auto_play, "controlPosition": control_position, @@ -65,6 +85,18 @@ def add_schema( "graphic": graphic_opts, "checkpointStyle": checkpointstyle_opts, "controlStyle": controlstyle_opts, + "progress": { + "lineStyle": progress_linestyle_opts, + "itemStyle": progress_itemstyle_opts, + "label": progress_label_opts, + }, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, } ) return self @@ -88,6 +120,14 @@ def add(self, chart: Base, time_point: str): "color": chart.options.get("color"), "graphic": chart.options.get("graphic"), "bmap": chart.options.get("bmap"), + "toolbox": chart.options.get("toolbox"), + "dataset": chart.options.get("dataset"), + "radiusAxis": chart.options.get("radiusAxis"), + "angleAxis": chart.options.get("angleAxis"), + "xAxis3D": chart.options.get("xAxis3D"), + "yAxis3D": chart.options.get("yAxis3D"), + "zAxis3D": chart.options.get("zAxis3D"), + "grid3D": chart.options.get("grid3D"), } ) self.__check_components(chart) @@ -107,6 +147,7 @@ def __check_components(self, chart: Base): "visualMap", "dataZoom", "parallelAxis", + "legend", ] for component in components: diff --git a/pyecharts/charts/mixins.py b/pyecharts/charts/mixins.py index 10bf45129..a45b59d89 100644 --- a/pyecharts/charts/mixins.py +++ b/pyecharts/charts/mixins.py @@ -7,6 +7,11 @@ def add_js_funcs(self, *fns): self.js_functions.add(fn) return self + def add_js_events(self, *fns): + for fn in fns: + self.js_events.add(fn) + return self + def load_javascript(self): return engine.load_javascript(self) diff --git a/pyecharts/charts/three_axis_charts/bar3D.py b/pyecharts/charts/three_axis_charts/bar3D.py index 0c020dd11..8958a8a98 100644 --- a/pyecharts/charts/three_axis_charts/bar3D.py +++ b/pyecharts/charts/three_axis_charts/bar3D.py @@ -1,6 +1,7 @@ from ... import types from ...charts.chart import ThreeAxisChart -from ...options import InitOpts +from ...globals import ChartType +from ...options import InitOpts, RenderOpts class Bar3D(ThreeAxisChart): @@ -8,6 +9,10 @@ class Bar3D(ThreeAxisChart): <<< 3D Bar-Chart >>> """ - def __init__(self, init_opts: types.Init = InitOpts()): - super().__init__(init_opts) - self._3d_chart_type = "bar3D" + def __init__( + self, + init_opts: types.Init = InitOpts(), + render_opts: types.RenderInit = RenderOpts(), + ): + super().__init__(init_opts, render_opts) + self._3d_chart_type = ChartType.BAR3D diff --git a/pyecharts/charts/three_axis_charts/graph_gl.py b/pyecharts/charts/three_axis_charts/graph_gl.py new file mode 100644 index 000000000..f2a88293a --- /dev/null +++ b/pyecharts/charts/three_axis_charts/graph_gl.py @@ -0,0 +1,51 @@ +from ... import options as opts +from ... import types +from ...charts.chart import Chart3D +from ...globals import ChartType +from ...options import InitOpts, RenderOpts + + +class GraphGL(Chart3D): + """ + <<< GraphGL Relational graphs using WebGL to support the layout and + drawing of large-scale network/relational data. >>> + """ + + def __init__( + self, + init_opts: types.Init = InitOpts(), + render_opts: types.RenderInit = RenderOpts(), + ): + super().__init__(init_opts, render_opts) + self._3d_chart_type = ChartType.GRAPHGL + + def add( + self, + series_name: str, + nodes: types.Sequence[types.GraphGLNode], + links: types.Sequence[types.GraphGLLink], + *, + layout: str = "forceAtlas2", + force_atlas2_opts: types.GraphGLForceAtlas2 = None, + symbol: types.Optional[str] = "circle", + symbol_size: types.Numeric = 5, + itemstyle_opts: types.ItemStyle = None, + linestyle_opts: types.LineStyle = opts.LineStyleOpts(), + z_level: types.Numeric = 10, + ): + self.options.get("series").append( + { + "type": ChartType.GRAPHGL, + "name": series_name, + "layout": layout, + "forceAtlas2": force_atlas2_opts, + "nodes": nodes, + "links": links, + "symbol": symbol, + "symbolSize": symbol_size, + "itemStyle": itemstyle_opts, + "lineStyle": linestyle_opts, + "zlevel": z_level, + } + ) + return self diff --git a/pyecharts/charts/three_axis_charts/line3D.py b/pyecharts/charts/three_axis_charts/line3D.py index d96fd991e..67d2230b9 100644 --- a/pyecharts/charts/three_axis_charts/line3D.py +++ b/pyecharts/charts/three_axis_charts/line3D.py @@ -1,6 +1,7 @@ from ... import types from ...charts.chart import ThreeAxisChart -from ...options import InitOpts +from ...globals import ChartType +from ...options import InitOpts, RenderOpts class Line3D(ThreeAxisChart): @@ -8,6 +9,10 @@ class Line3D(ThreeAxisChart): <<< 3D Line-Chart >>> """ - def __init__(self, init_opts: types.Init = InitOpts()): - super().__init__(init_opts) - self._3d_chart_type = "line3D" + def __init__( + self, + init_opts: types.Init = InitOpts(), + render_opts: types.RenderInit = RenderOpts(), + ): + super().__init__(init_opts, render_opts) + self._3d_chart_type = ChartType.LINE3D diff --git a/pyecharts/charts/three_axis_charts/lines3D.py b/pyecharts/charts/three_axis_charts/lines3D.py new file mode 100644 index 000000000..e0948b456 --- /dev/null +++ b/pyecharts/charts/three_axis_charts/lines3D.py @@ -0,0 +1,66 @@ +from ... import options as opts +from ... import types +from ...charts.chart import Chart3D +from ...globals import ChartType +from ...options import InitOpts, RenderOpts + + +class Lines3D(Chart3D): + """ + Lines 3D + """ + + def __init__( + self, + init_opts: types.Init = InitOpts(), + render_opts: types.RenderInit = RenderOpts(), + ): + super().__init__(init_opts, render_opts) + self._3d_chart_type = ChartType.LINES3D + + def add( + self, + series_name: str, + data_pair: types.Sequence, + coordinate_system: str, + *, + geo_3d_index: types.Numeric = 0, + globe_index: types.Numeric = 0, + is_polyline: bool = False, + is_show_lines_effect: bool = False, + lines_effect_period: types.Numeric = 4, + lines_effect_constant_speed: types.Optional[types.Numeric] = None, + lines_effect_trail_width: types.Numeric = 4, + lines_effect_trail_length: types.Numeric = 0.1, + lines_effect_trail_color: types.Optional[str] = None, + lines_effect_trail_opacity: types.Optional[types.Numeric] = None, + blend_mode: str = "source-over", + linestyle_opts: types.Optional[types.LineStyle] = None, + z_level: types.Numeric = -10, + is_silent: bool = False, + ): + self.options.get("series").append( + { + "type": ChartType.LINES3D, + "name": series_name, + "data": data_pair, + "coordinateSystem": coordinate_system, + "geo3DIndex": geo_3d_index, + "globeIndex": globe_index, + "polyline": is_polyline, + "effect": { + "show": is_show_lines_effect, + "period": lines_effect_period, + "constantSpeed": lines_effect_constant_speed, + "trailWidth": lines_effect_trail_width, + "trailLength": lines_effect_trail_length, + "trailColor": lines_effect_trail_color, + "trailOpacity": lines_effect_trail_opacity, + }, + "lineStyle": linestyle_opts, + "blendMode": blend_mode, + "zlevel": z_level, + "silent": is_silent, + } + ) + return self diff --git a/pyecharts/charts/three_axis_charts/map3D.py b/pyecharts/charts/three_axis_charts/map3D.py index 01617697c..4a6086295 100644 --- a/pyecharts/charts/three_axis_charts/map3D.py +++ b/pyecharts/charts/three_axis_charts/map3D.py @@ -2,7 +2,7 @@ from ... import types from ...charts.chart import Chart3D from ...globals import ChartType -from ...options import InitOpts +from ...options import InitOpts, RenderOpts class Map3D(Chart3D): @@ -10,9 +10,13 @@ class Map3D(Chart3D): 3D map """ - def __init__(self, init_opts: types.Init = InitOpts()): - super().__init__(init_opts) - self._3d_chart_type = "map3D" + def __init__( + self, + init_opts: types.Init = InitOpts(), + render_opts: types.RenderInit = RenderOpts(), + ): + super().__init__(init_opts, render_opts) + self._3d_chart_type = ChartType.MAP3D def add( self, @@ -21,7 +25,6 @@ def add( *, type_: ChartType = None, maptype: str = "china", - is_selected: bool = True, is_map_symbol_show: bool = True, grid_3d_index: types.Numeric = 0, geo_3d_index: types.Numeric = 0, @@ -56,7 +59,7 @@ def add( data = [{"name": n, "value": v} for n, v in data_pair] else: data = data_pair - self._append_legend(series_name, is_selected) + self._append_legend(series_name) if type_ is None or type_ == ChartType.MAP3D: self.options.get("series").append( { diff --git a/pyecharts/charts/three_axis_charts/map_globe.py b/pyecharts/charts/three_axis_charts/map_globe.py index 6f72ad756..868be02bf 100644 --- a/pyecharts/charts/three_axis_charts/map_globe.py +++ b/pyecharts/charts/three_axis_charts/map_globe.py @@ -7,7 +7,7 @@ from ...charts.chart import Chart3D from ...commons import utils from ...globals import CurrentConfig, NotebookType -from ...options import InitOpts +from ...options import InitOpts, RenderOpts from ...render.display import HTML from ...render.engine import RenderEngine @@ -17,8 +17,12 @@ class MapGlobe(Chart3D, MapMixin): Globe Map """ - def __init__(self, init_opts: types.Init = InitOpts()): - super().__init__(init_opts) + def __init__( + self, + init_opts: types.Init = InitOpts(), + render_opts: types.RenderInit = RenderOpts(), + ): + super().__init__(init_opts, render_opts) def add_schema(self, maptype: str = "china"): self.js_dependencies.add(maptype) diff --git a/pyecharts/charts/three_axis_charts/scatter3D.py b/pyecharts/charts/three_axis_charts/scatter3D.py index 763b781dd..0b43dd380 100644 --- a/pyecharts/charts/three_axis_charts/scatter3D.py +++ b/pyecharts/charts/three_axis_charts/scatter3D.py @@ -1,6 +1,7 @@ from ... import types from ...charts.chart import ThreeAxisChart -from ...options import InitOpts +from ...globals import ChartType +from ...options import InitOpts, RenderOpts class Scatter3D(ThreeAxisChart): @@ -8,6 +9,10 @@ class Scatter3D(ThreeAxisChart): <<< 3D Scatter-Chart >>> """ - def __init__(self, init_opts: types.Init = InitOpts()): - super().__init__(init_opts) - self._3d_chart_type = "scatter3D" + def __init__( + self, + init_opts: types.Init = InitOpts(), + render_opts: types.RenderInit = RenderOpts(), + ): + super().__init__(init_opts, render_opts) + self._3d_chart_type = ChartType.SCATTER3D diff --git a/pyecharts/charts/three_axis_charts/surface3D.py b/pyecharts/charts/three_axis_charts/surface3D.py index 5659d7ce0..9727d89b3 100644 --- a/pyecharts/charts/three_axis_charts/surface3D.py +++ b/pyecharts/charts/three_axis_charts/surface3D.py @@ -1,6 +1,8 @@ +from ... import options as opts from ... import types from ...charts.chart import ThreeAxisChart -from ...options import InitOpts +from ...globals import ChartType +from ...options import InitOpts, RenderOpts class Surface3D(ThreeAxisChart): @@ -8,6 +10,10 @@ class Surface3D(ThreeAxisChart): <<< 3D Surface-Chart >>> """ - def __init__(self, init_opts: types.Init = InitOpts()): - super().__init__(init_opts) - self._3d_chart_type = "surface" + def __init__( + self, + init_opts: types.Init = InitOpts(), + render_opts: types.RenderInit = RenderOpts(), + ): + super().__init__(init_opts, render_opts) + self._3d_chart_type = ChartType.SURFACE diff --git a/pyecharts/commons/utils.py b/pyecharts/commons/utils.py index 2da93772c..fa4e4951e 100644 --- a/pyecharts/commons/utils.py +++ b/pyecharts/commons/utils.py @@ -32,6 +32,9 @@ def produce_require_dict(js_dependencies, js_host) -> dict: if name.startswith("https://api.map.baidu.com"): confs.append("'baidu_map_api{}':'{}'".format(len(name), name)) libraries.append("'baidu_map_api{}'".format(len(name))) + if name.startswith("https://webapi.amap.com"): + confs.append("'amap_map_api{}':'{}'".format(len(name), name)) + libraries.append("'amap_map_api{}'".format(len(name))) if name in FILENAMES: f, _ = FILENAMES[name] confs.append("'{}':'{}{}'".format(name, js_host, f)) @@ -54,14 +57,14 @@ def replace_placeholder_with_quotes(html: str) -> str: return re.sub("--x_x--0_0--", "", html) -def _flat(obj): - if hasattr(obj, "js_dependencies"): - return list(obj.js_dependencies) - - if isinstance(obj, (list, tuple, set)): - return obj - - return (obj,) # tuple +# def _flat(obj): +# if hasattr(obj, "js_dependencies"): +# return list(obj.js_dependencies) +# +# if isinstance(obj, (list, tuple, set)): +# return obj +# +# return (obj,) # tuple def _expand(dict_generator): @@ -77,6 +80,13 @@ def _clean_dict(mydict): elif isinstance(value, (list, tuple, set)): value = list(_clean_array(value)) + # Not elegant, but effective and less code-intrusive. + elif type(value).__name__ in ["ndarray", "Series"]: + raise ValueError( + "Can't use non-native data structures " + "as axis data to render chart" + ) + elif isinstance(value, str) and not value: # delete key with empty string continue diff --git a/pyecharts/components/table.py b/pyecharts/components/table.py index 3b8141b26..fe85f5cc8 100644 --- a/pyecharts/components/table.py +++ b/pyecharts/components/table.py @@ -22,9 +22,15 @@ def __init__(self, page_title: str = CurrentConfig.PAGE_TITLE, js_host: str = "" self._component_type: str = "table" self.chart_id: str = uuid.uuid4().hex - def add(self, headers: Sequence, rows: Sequence, attributes: Optional[dict] = None): + def add( + self, + headers: Sequence, + rows: Sequence, + attributes: Optional[dict] = None, + **kwargs, + ): attributes = attributes or {"class": "fl-table"} - table = PrettyTable(headers, attributes=attributes) + table = PrettyTable(headers, attributes=attributes, **kwargs) for r in rows: table.add_row(r) self.html_content = table.get_html_string() diff --git a/pyecharts/datasets/__init__.py b/pyecharts/datasets/__init__.py index 630291ca6..c76dffe99 100644 --- a/pyecharts/datasets/__init__.py +++ b/pyecharts/datasets/__init__.py @@ -72,10 +72,7 @@ def _search(self, lookfor: typing.Any, stop_on_first: bool = False): return best_ratio >= self.cutoff, best_key, best_match, best_ratio def __contains__(self, item: typing.Any): - if self._search(item, True)[0]: - return True - else: - return False + return self._search(item, True)[0] def __getitem__(self, lookfor: typing.Any): matched, key, item, ratio = self._search(lookfor) diff --git a/pyecharts/datasets/map_filename.json b/pyecharts/datasets/map_filename.json index e6b23443e..37b63015f 100644 --- a/pyecharts/datasets/map_filename.json +++ b/pyecharts/datasets/map_filename.json @@ -1,4 +1,9 @@ { + "amap": ["echarts-extension-amap.min", "js"], + "lmap": ["echarts-extension-leaflet.min", "js"], + "lmap-src": ["leaflet/leaflet", "js"], + "lmap-css": ["leaflet/leaflet", "css"], + "gmap": ["echarts-extension-gmap.min", "js"], "bulma": ["bulma.min", "css"], "jquery": ["jquery.min", "js"], "jquery-ui": ["jquery-ui.min", "js"], @@ -7,6 +12,14 @@ "echarts-gl": ["echarts-gl.min", "js"], "echarts-liquidfill": ["echarts-liquidfill.min", "js"], "echarts-wordcloud": ["echarts-wordcloud.min", "js"], + "echarts-stat": ["ecStat.min", "js"], + "echarts-x-violin": ["echarts-x/violin/index.auto.min", "js"], + "echarts-x-stage": ["echarts-x/stage/index.auto.min", "js"], + "echarts-x-contour-d3": ["echarts-x/contour/d3.min", "js"], + "echarts-x-contour": ["echarts-x/contour/index.auto.min", "js"], + "echarts-x-segmented-doughnut": ["echarts-x/segmented-doughnut/index.auto.min", "js"], + "echarts-x-line-range": ["echarts-x/line-range/index.auto.min", "js"], + "echarts-x-bar-range": ["echarts-x/bar-range/index.auto.min", "js"], "bmap": ["bmap.min", "js"], "chalk": ["themes/chalk", "js"], "essos": ["themes/essos", "js"], diff --git a/pyecharts/faker.py b/pyecharts/faker.py index cf551eb5f..cc0e8cbc9 100644 --- a/pyecharts/faker.py +++ b/pyecharts/faker.py @@ -30,7 +30,7 @@ class _Faker: "#a50026", ] months = ["{}月".format(i) for i in range(1, 13)] - provinces = ["广东", "北京", "上海", "江西", "湖南", "浙江", "江苏"] + provinces = ["广东省", "北京市", "上海市", "江西省", "湖南省", "浙江省", "江苏省"] guangdong_city = ["汕头市", "汕尾市", "揭阳市", "阳江市", "肇庆市", "广州市", "惠州市"] country = [ "China", @@ -100,241 +100,3 @@ class Collector: @staticmethod def funcs(fn): Collector.charts.append((fn, fn.__name__)) - - -POPULATION = [ - ["Country (or dependency)", "Population\n(2019)"], - ["China", 1420062022], - ["India", 1368737513], - ["United States", 329093110], - ["Indonesia", 269536482], - ["Brazil", 212392717], - ["Pakistan", 204596442], - ["Nigeria", 200962417], - ["Bangladesh", 168065920], - ["Russia", 143895551], - ["Mexico", 132328035], - ["Japan", 126854745], - ["Ethiopia", 110135635], - ["Philippines", 108106310], - ["Egypt", 101168745], - ["Vietnam", 97429061], - ["DR Congo", 86727573], - ["Turkey", 82961805], - ["Iran", 82820766], - ["Germany", 82438639], - ["Thailand", 69306160], - ["United Kingdom", 66959016], - ["France", 65480710], - ["Tanzania", 60913557], - ["Italy", 59216525], - ["South Africa", 58065097], - ["Myanmar", 54336138], - ["Kenya", 52214791], - ["South Korea", 51339238], - ["Colombia", 49849818], - ["Spain", 46441049], - ["Uganda", 45711874], - ["Argentina", 45101781], - ["Ukraine", 43795220], - ["Algeria", 42679018], - ["Sudan", 42514094], - ["Iraq", 40412299], - ["Poland", 38028278], - ["Canada", 37279811], - ["Afghanistan", 37209007], - ["Morocco", 36635156], - ["Saudi Arabia", 34140662], - ["Peru", 32933835], - ["Uzbekistan", 32807368], - ["Venezuela", 32779868], - ["Malaysia", 32454455], - ["Angola", 31787566], - ["Mozambique", 31408823], - ["Ghana", 30096970], - ["Nepal", 29942018], - ["Yemen", 29579986], - ["Madagascar", 26969642], - ["North Korea", 25727408], - ["Côte d'Ivoire", 25531083], - ["Cameroon", 25312993], - ["Australia", 25088636], - ["Taiwan", 23758247], - ["Niger", 23176691], - ["Sri Lanka", 21018859], - ["Burkina Faso", 20321560], - ["Malawi", 19718743], - ["Mali", 19689140], - ["Romania", 19483360], - ["Kazakhstan", 18592970], - ["Syria", 18499181], - ["Chile", 18336653], - ["Zambia", 18137369], - ["Guatemala", 17577842], - ["Zimbabwe", 17297495], - ["Netherlands", 17132908], - ["Ecuador", 17100444], - ["Senegal", 16743859], - ["Cambodia", 16482646], - ["Chad", 15814345], - ["Somalia", 15636171], - ["Guinea", 13398180], - ["South Sudan", 13263184], - ["Rwanda", 12794412], - ["Benin", 11801595], - ["Tunisia", 11783168], - ["Burundi", 11575964], - ["Belgium", 11562784], - ["Cuba", 11492046], - ["Bolivia", 11379861], - ["Haiti", 11242856], - ["Greece", 11124603], - ["Dominican Republic", 10996774], - ["Czechia", 10630589], - ["Portugal", 10254666], - ["Jordan", 10069794], - ["Sweden", 10053135], - ["Azerbaijan", 10014575], - ["United Arab Emirates", 9682088], - ["Hungary", 9655361], - ["Honduras", 9568688], - ["Belarus", 9433874], - ["Tajikistan", 9292000], - ["Austria", 8766201], - ["Serbia", 8733407], - ["Switzerland", 8608259], - ["Papua New Guinea", 8586525], - ["Israel", 8583916], - ["Togo", 8186384], - ["Sierra Leone", 7883123], - ["Hong Kong", 7490776], - ["Laos", 7064242], - ["Bulgaria", 6988739], - ["Paraguay", 6981981], - ["Libya", 6569864], - ["El Salvador", 6445405], - ["Nicaragua", 6351157], - ["Kyrgyzstan", 6218616], - ["Lebanon", 6065922], - ["Turkmenistan", 5942561], - ["Singapore", 5868104], - ["Denmark", 5775224], - ["Finland", 5561389], - ["Congo", 5542197], - ["Slovakia", 5450987], - ["Norway", 5400916], - ["Eritrea", 5309659], - ["State of Palestine", 5186790], - ["Oman", 5001875], - ["Costa Rica", 4999384], - ["Liberia", 4977720], - ["Ireland", 4847139], - ["Central African Republic", 4825711], - ["New Zealand", 4792409], - ["Mauritania", 4661149], - ["Kuwait", 4248974], - ["Panama", 4226197], - ["Croatia", 4140148], - ["Moldova", 4029750], - ["Georgia", 3904204], - ["Puerto Rico", 3654978], - ["Bosnia and Herzegovina", 3501774], - ["Uruguay", 3482156], - ["Mongolia", 3166244], - ["Albania", 2938428], - ["Armenia", 2936706], - ["Jamaica", 2906339], - ["Lithuania", 2864459], - ["Qatar", 2743901], - ["Namibia", 2641996], - ["Botswana", 2374636], - ["Lesotho", 2292682], - ["Gambia", 2228075], - ["Gabon", 2109099], - ["North Macedonia", 2086720], - ["Slovenia", 2081900], - ["Guinea-Bissau", 1953723], - ["Latvia", 1911108], - ["Bahrain", 1637896], - ["Swaziland", 1415414], - ["Trinidad and Tobago", 1375443], - ["Equatorial Guinea", 1360104], - ["Timor-Leste", 1352360], - ["Estonia", 1303798], - ["Mauritius", 1271368], - ["Cyprus", 1198427], - ["Djibouti", 985690], - ["Fiji", 918757], - ["Réunion", 889918], - ["Comoros", 850910], - ["Bhutan", 826229], - ["Guyana", 786508], - ["Macao", 642090], - ["Solomon Islands", 635254], - ["Montenegro", 629355], - ["Luxembourg", 596992], - ["Western Sahara", 582478], - ["Suriname", 573085], - ["Cabo Verde", 560349], - ["Micronesia", 536579], - ["Maldives", 451738], - ["Guadeloupe", 448798], - ["Brunei", 439336], - ["Malta", 433245], - ["Bahamas", 403095], - ["Belize", 390231], - ["Martinique", 385320], - ["Iceland", 340566], - ["French Guiana", 296847], - ["French Polynesia", 288506], - ["Vanuatu", 288017], - ["Barbados", 287010], - ["New Caledonia", 283376], - ["Mayotte", 266380], - ["Sao Tome & Principe", 213379], - ["Samoa", 198909], - ["Saint Lucia", 180454], - ["Guam", 167245], - ["Channel Islands", 166828], - ["Curaçao", 162547], - ["Kiribati", 120428], - ["St. Vincent & Grenadines", 110488], - ["Tonga", 110041], - ["Grenada", 108825], - ["Aruba", 106053], - ["U.S. Virgin Islands", 104909], - ["Antigua and Barbuda", 104084], - ["Seychelles", 95702], - ["Isle of Man", 85369], - ["Andorra", 77072], - ["Dominica", 74679], - ["Cayman Islands", 63129], - ["Bermuda", 60833], - ["Greenland", 56673], - ["Saint Kitts & Nevis", 56345], - ["American Samoa", 55727], - ["Northern Mariana Islands", 55246], - ["Marshall Islands", 53211], - ["Faeroe Islands", 49692], - ["Sint Maarten", 40939], - ["Monaco", 39102], - ["Liechtenstein", 38404], - ["Turks and Caicos", 36461], - ["Gibraltar", 34879], - ["San Marino", 33683], - ["British Virgin Islands", 32206], - ["Caribbean Netherlands", 25971], - ["Palau", 22206], - ["Cook Islands", 17462], - ["Anguilla", 15174], - ["Wallis & Futuna", 11617], - ["Tuvalu", 11393], - ["Nauru", 11260], - ["Saint Pierre & Miquelon", 6375], - ["Montserrat", 5220], - ["Saint Helena", 4096], - ["Falkland Islands", 2921], - ["Niue", 1628], - ["Tokelau", 1340], - ["Holy See", 799], -] diff --git a/pyecharts/globals.py b/pyecharts/globals.py index 2179e0556..1d2d18e69 100644 --- a/pyecharts/globals.py +++ b/pyecharts/globals.py @@ -10,6 +10,11 @@ class _RenderType: SVG: str = "svg" +class _Locale: + EN: str = "EN" + ZH: str = "ZH" + + class _FileType: SVG: str = "svg" PNG: str = "png" @@ -29,16 +34,20 @@ class _ChartType: BAR: str = "bar" BAR3D: str = "bar3D" BOXPLOT: str = "boxplot" + CHORD: str = "chord" EFFECT_SCATTER: str = "effectScatter" FUNNEL: str = "funnel" + FLOWGL: str = "flowGL" GAUGE: str = "gauge" GEO: str = "geo" GRAPH: str = "graph" + GRAPHGL: str = "graphGL" HEATMAP: str = "heatmap" KLINE: str = "candlestick" LINE: str = "line" LINE3D: str = "line3D" LINES: str = "lines" + LINESGL: str = "linesGL" LINES3D: str = "lines3D" LIQUID: str = "liquidFill" MAP: str = "map" @@ -51,12 +60,21 @@ class _ChartType: SANKEY: str = "sankey" SCATTER: str = "scatter" SCATTER3D: str = "scatter3D" + SCATTERGL: str = "scatterGL" SUNBURST: str = "sunburst" + SURFACE: str = "surface" THEMERIVER: str = "themeRiver" TREE: str = "tree" TREEMAP: str = "treemap" WORDCLOUD: str = "wordCloud" CUSTOM: str = "custom" + # below chart types are Echarts 6 new custom chart + VIOLIN: str = "violin" + STAGE: str = "stage" + DOUGHNUT: str = "segmentedDoughnut" + CONTOUR: str = "contour" + BAR_RANGE: str = "barRange" + LINE_RANGE: str = "lineRange" ToolTipFormatterType = { @@ -123,15 +141,16 @@ class _NotebookType: class _OnlineHost: - DEFAULT_HOST = "https://assets.pyecharts.org/assets/" + DEFAULT_HOST = "https://assets.pyecharts.org/assets/v6/" NOTEBOOK_HOST = "http://localhost:8888/nbextensions/assets/" -class _WarningControl: - ShowWarning = True +class _RenderSepType: + SepType = os.linesep RenderType = _RenderType() +Locale = _Locale() FileType = _FileType() SymbolType = _SymbolType() ChartType = _ChartType @@ -140,13 +159,15 @@ class _WarningControl: BMapType = _BMapType NotebookType = _NotebookType() OnlineHostType = _OnlineHost() -WarningType = _WarningControl() +RenderSepType = _RenderSepType() +DefaultLocale = Locale.ZH class _CurrentConfig: PAGE_TITLE = "Awesome-pyecharts" ONLINE_HOST = OnlineHostType.DEFAULT_HOST NOTEBOOK_TYPE = NotebookType.JUPYTER_NOTEBOOK + LOCALE = DefaultLocale GLOBAL_ENV = Environment( keep_trailing_newline=True, trim_blocks=True, diff --git a/pyecharts/options/__init__.py b/pyecharts/options/__init__.py index dd58ccf67..704104fcf 100644 --- a/pyecharts/options/__init__.py +++ b/pyecharts/options/__init__.py @@ -11,12 +11,24 @@ BMapTypeControlOpts, BoxplotItem, CandleStickItem, + ChordData, + ChordLink, ComponentTitleOpts, + CustomBarRangeItemPayloadOpts, + CustomContourItemPayloadOpts, + CustomLineRangeItemPayloadOpts, + CustomSegmentedDoughnutItemPayloadOpts, + CustomStageItemPayloadOpts, + CustomViolinItemPayloadOpts, EffectScatterItem, FunnelItem, GaugeDetailOpts, GaugePointerOpts, + GaugeAnchorOpts, + GaugeProgressOpts, GaugeTitleOpts, + GeoItem, + GeoRegionsOpts, GraphCategory, GraphicBasicStyleOpts, GraphicGroup, @@ -29,6 +41,8 @@ GraphicTextStyleOpts, GraphLink, GraphNode, + GraphGLLink, + GraphGLNode, LineItem, MapItem, Map3DColorMaterialOpts, @@ -39,12 +53,18 @@ Map3DRealisticMaterialOpts, Map3DViewControlOpts, PageLayoutOpts, + ParallelItem, PieItem, PieLabelLineOpts, + PieEmptyCircleStyle, RadarItem, SankeyLevelsOpts, ScatterItem, SunburstItem, + SunburstLabelLayoutOpts, + SunburstLabelLineOpts, + SunburstLevelOpts, + TabChartGlobalOpts, ThemeRiverItem, TimelineCheckPointerStyle, TimelineControlStyle, @@ -56,28 +76,50 @@ AngleAxisItem, AngleAxisOpts, AnimationOpts, + AriaDecalOpts, + AriaLabelOpts, + AriaOpts, Axis3DOpts, + AxisBreakOpts, + AxisBreakAreaOpts, + AxisBreakLabelLayoutOpts, AxisLineOpts, AxisOpts, AxisPointerOpts, AxisTickOpts, + BlurOpts, BrushOpts, CalendarOpts, CalendarDayLabelOpts, CalendarMonthLabelOpts, CalendarYearLabelOpts, DataZoomOpts, + DatasetTransformOpts, + EmphasisOpts, + Emphasis3DOpts, Grid3DOpts, GridOpts, + GridOuterOpts, InitOpts, + RenderOpts, LegendOpts, + MatrixAxisOpts, + MatrixAxisDataOpts, + MatrixBackgroundStyleOpts, + MatrixBodyDataOpts, + MatrixBodyOrCornerOpts, + MatrixDividerLineStyleOpts, + MatrixOpts, ParallelAxisOpts, ParallelOpts, PolarOpts, RadarIndicatorItem, RadiusAxisItem, RadiusAxisOpts, + SelectOpts, SingleAxisOpts, + ThumbnailOpts, + ThumbnailWindowStyleOpts, TitleOpts, ToolBoxFeatureBrushOpts, ToolBoxFeatureDataViewOpts, @@ -88,11 +130,13 @@ ToolBoxFeatureSaveAsImageOpts, ToolboxOpts, TooltipOpts, + TreeLeavesOpts, VisualMapOpts, ) from .series_options import ( AreaStyleOpts, EffectOpts, + GraphGLForceAtlas2Opts, ItemStyleOpts, LabelOpts, LineStyleOpts, diff --git a/pyecharts/options/charts_options.py b/pyecharts/options/charts_options.py index cae6d369a..17099cf78 100644 --- a/pyecharts/options/charts_options.py +++ b/pyecharts/options/charts_options.py @@ -17,450 +17,239 @@ ) -# Data Item -class BarItem(BasicOpts): +# Chart Options +class ChordData(BasicOpts): def __init__( self, - name: Union[int, str], - value: Numeric, - *, - label_opts: Union[LabelOpts, dict, None] = None, - itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, - tooltip_opts: Union[TooltipOpts, dict, None] = None, + name: Optional[str] = None, ): self.opts: dict = { "name": name, - "value": value, - "label": label_opts, - "itemStyle": itemstyle_opts, - "tooltip": tooltip_opts, } -class BoxplotItem(BasicOpts): +class ChordLink(BasicOpts): def __init__( self, - name: Union[int, str], - value: Sequence, - *, - itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, - tooltip_opts: Union[TooltipOpts, dict, None] = None, + source: Union[str, int, None] = None, + target: Union[str, int, None] = None, + value: Optional[Numeric] = None, ): self.opts: dict = { - "name": name, + "source": source, + "target": target, "value": value, - "itemStyle": itemstyle_opts, - "tooltip": tooltip_opts, } -class CandleStickItem(BasicOpts): +class GraphNode(BasicOpts): def __init__( self, - name: Union[str, int], - value: Sequence, - *, + name: Optional[str] = None, + x: Optional[Numeric] = None, + y: Optional[Numeric] = None, + is_fixed: bool = False, + value: Union[str, Sequence, None] = None, + category: Optional[int] = None, + symbol: Optional[str] = None, + symbol_size: Union[Numeric, Sequence, None] = None, + symbol_rotate: Optional[int] = None, itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + label_opts: Union[LabelOpts, dict, None] = None, + is_disabled_emphasis: Optional[bool] = None, + emphasis_itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + emphasis_label_opts: Union[LabelOpts, dict, None] = None, + blur_itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + blur_label_opts: Union[LabelOpts, dict, None] = None, + is_disabled_select: Optional[bool] = None, + select_itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + select_label_opts: Union[LabelOpts, dict, None] = None, tooltip_opts: Union[TooltipOpts, dict, None] = None, ): self.opts: dict = { "name": name, + "x": x, + "y": y, + "fixed": is_fixed, "value": value, + "category": category, + "symbol": symbol, + "symbolSize": symbol_size, + "symbolRotate": symbol_rotate, "itemStyle": itemstyle_opts, + "label": label_opts, + "emphasis": { + "disabled": is_disabled_emphasis, + "itemStyle": emphasis_itemstyle_opts, + "label": emphasis_label_opts, + }, + "blur": { + "itemStyle": blur_itemstyle_opts, + "label": blur_label_opts, + }, + "select": { + "disabled": is_disabled_select, + "itemStyle": select_itemstyle_opts, + "label": select_label_opts, + }, "tooltip": tooltip_opts, } -class EffectScatterItem(BasicOpts): +class GraphLink(BasicOpts): def __init__( self, - name: Union[str, Numeric], - value: Union[str, Numeric], - *, - symbol: Optional[str] = None, - symbol_size: Union[Sequence[Numeric], Numeric] = None, - symbol_rotate: Optional[Numeric] = None, - symbol_keep_aspect: bool = False, - symbol_offset: Optional[Sequence] = None, + source: Union[str, int, None] = None, + target: Union[str, int, None] = None, + value: Optional[Numeric] = None, + symbol: Union[str, Sequence, None] = None, + symbol_size: Union[Numeric, Sequence, None] = None, + linestyle_opts: Union[LineStyleOpts, dict, None] = None, label_opts: Union[LabelOpts, dict, None] = None, - itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, - tooltip_opts: Union[TooltipOpts, dict, None] = None, + is_disabled_emphasis: Optional[bool] = None, + emphasis_linestyle_opts: Union[LineStyleOpts, dict, None] = None, + emphasis_label_opts: Union[LabelOpts, dict, None] = None, + blur_linestyle_opts: Union[LineStyleOpts, dict, None] = None, + blur_label_opts: Union[LabelOpts, dict, None] = None, + is_disabled_select: Optional[bool] = None, + select_linestyle_opts: Union[LineStyleOpts, dict, None] = None, + select_label_opts: Union[LabelOpts, dict, None] = None, + is_ignore_force_layout: bool = False ): self.opts: dict = { - "name": name, + "source": source, + "target": target, "value": value, "symbol": symbol, "symbolSize": symbol_size, - "symbolRotate": symbol_rotate, - "symbolKeepAspect": symbol_keep_aspect, - "symbolOffset": symbol_offset, + "lineStyle": linestyle_opts, "label": label_opts, - "itemStyle": itemstyle_opts, - "tooltip": tooltip_opts, + "emphasis": { + "disabled": is_disabled_emphasis, + "lineStyle": emphasis_linestyle_opts, + "label": emphasis_label_opts, + }, + "blur": { + "lineStyle": blur_linestyle_opts, + "label": blur_label_opts, + }, + "select": { + "disabled": is_disabled_select, + "lineStyle": select_linestyle_opts, + "label": select_label_opts, + }, + "ignoreForceLayout": is_ignore_force_layout, } -class FunnelItem(BasicOpts): +class GraphCategory(BasicOpts): def __init__( self, - name: Union[str, int], - value: Union[Sequence, str, Numeric], - *, - is_show_label_line: Optional[bool] = None, - label_line_width: Optional[int] = None, - label_line_linestyle_opts: Union[LineStyleOpts, dict, None] = None, + name: Optional[str] = None, + symbol: Optional[str] = None, + symbol_size: Union[Numeric, Sequence, None] = None, label_opts: Union[LabelOpts, dict, None] = None, - itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, - tooltip_opts: Union[TooltipOpts, dict, None] = None, ): self.opts: dict = { "name": name, - "value": value, - "labelLine": { - "show": is_show_label_line, - "length": label_line_width, - "lineStyle": label_line_linestyle_opts, - }, + "symbol": symbol, + "symbolSize": symbol_size, "label": label_opts, - "itemStyle": itemstyle_opts, - "tooltip": tooltip_opts, } -class LineItem(BasicOpts): +class BMapNavigationControlOpts(BasicOpts): def __init__( self, - name: Union[str, Numeric] = None, - value: Union[str, Numeric] = None, - *, - symbol: Optional[str] = "circle", - symbol_size: Numeric = 4, - symbol_rotate: Optional[Numeric] = None, - symbol_keep_aspect: bool = False, - symbol_offset: Optional[Sequence] = None, - label_opts: Union[LabelOpts, dict, None] = None, - itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, - tooltip_opts: Union[TooltipOpts, dict, None] = None, + position: Numeric = BMapType.ANCHOR_TOP_LEFT, + offset_width: Numeric = 10, + offset_height: Numeric = 10, + type_: Numeric = BMapType.NAVIGATION_CONTROL_LARGE, + is_show_zoom_info: bool = False, + is_enable_geo_location: bool = False, ): + bmap_nav_config = json.dumps( + { + "anchor": position, + "offset": {"width": offset_width, "height": offset_height}, + "type": type_, + "showZoomInfo": is_show_zoom_info, + "enableGeolocation": is_enable_geo_location, + } + ) + self.opts: dict = { - "name": name, - "value": value, - "symbol": symbol, - "symbolSize": symbol_size, - "symbolRotate": symbol_rotate, - "symbolKeepAspect": symbol_keep_aspect, - "symbolOffset": symbol_offset, - "label": label_opts, - "itemStyle": itemstyle_opts, - "tooltip": tooltip_opts, + "functions": [ + "bmap.addControl(new BMap.NavigationControl({}));".format( + bmap_nav_config + ) + ] } -class MapItem(BasicOpts): +class BMapOverviewMapControlOpts(BasicOpts): def __init__( self, - name: Optional[str] = None, - value: Union[Sequence, Numeric, str] = None, - is_selected: bool = False, - label_opts: Union[LabelOpts, dict, None] = None, - itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, - tooltip_opts: Union[TooltipOpts, dict, None] = None, + position: Numeric = BMapType.ANCHOR_BOTTOM_RIGHT, + offset_width: Numeric = 10, + offset_height: Numeric = 50, + is_open: bool = False, ): + bmap_overview_config = json.dumps( + { + "anchor": position, + "offset": {"width": offset_width, "height": offset_height}, + "isOpen": is_open, + } + ) + self.opts: dict = { - "name": name, - "value": value, - "selected": is_selected, - "label": label_opts, - "itemStyle": itemstyle_opts, - "tooltip": tooltip_opts, + "functions": [ + "var overview = new BMap.OverviewMapControl({});".format( + bmap_overview_config + ), + "bmap.addControl(overview);", + ] } -class PieItem(BasicOpts): +class BMapScaleControlOpts(BasicOpts): def __init__( self, - name: Optional[str] = None, - value: Optional[Numeric] = None, - is_selected: bool = False, - label_opts: Union[LabelOpts, dict, None] = None, - itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, - tooltip_opts: Union[TooltipOpts, dict, None] = None, + position: Numeric = BMapType.ANCHOR_BOTTOM_LEFT, + offset_width: Numeric = 80, + offset_height: Numeric = 21, ): + bmap_scale_config = json.dumps( + { + "anchor": position, + "offset": {"width": offset_width, "height": offset_height}, + } + ) + self.opts: dict = { - "name": name, - "value": value, - "selected": is_selected, - "label": label_opts, - "itemStyle": itemstyle_opts, - "tooltip": tooltip_opts, + "functions": [ + "bmap.addControl(new BMap.ScaleControl({}));".format(bmap_scale_config) + ] } -class RadarItem(BasicOpts): +class BMapTypeControlOpts(BasicOpts): def __init__( self, - name: Optional[str] = None, - value: Union[Sequence, Numeric, str] = None, - symbol: Optional[str] = None, - symbol_size: Union[Sequence[Numeric], Numeric] = None, - symbol_rotate: Optional[Numeric] = None, - symbol_keep_aspect: bool = False, - symbol_offset: Optional[Sequence] = None, - label_opts: Union[LabelOpts, dict, None] = None, - itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, - tooltip_opts: Union[TooltipOpts, dict, None] = None, - linestyle_opts: Union[LineStyleOpts, dict, None] = None, - areastyle_opts: Union[AreaStyleOpts, dict, None] = None, + position: Numeric = BMapType.ANCHOR_TOP_RIGHT, + type_: Numeric = BMapType.MAPTYPE_CONTROL_HORIZONTAL, ): + bmap_type_config = json.dumps({"anchor": position, "type": type_}) + self.opts: dict = { - "name": name, - "value": value, - "symbol": symbol, - "symbolSize": symbol_size, - "symbolRotate": symbol_rotate, - "symbolKeepAspect": symbol_keep_aspect, - "symbolOffset": symbol_offset, - "label": label_opts, - "itemStyle": itemstyle_opts, - "tooltip": tooltip_opts, - "lineStyle": linestyle_opts, - "areaStyle": areastyle_opts, + "functions": [ + "bmap.addControl(new BMap.MapTypeControl({}));".format(bmap_type_config) + ] } -class ScatterItem(BasicOpts): - def __init__( - self, - name: Union[str, Numeric] = None, - value: Union[str, Numeric] = None, - symbol: Optional[str] = None, - symbol_size: Union[Sequence[Numeric], Numeric] = None, - symbol_rotate: Optional[Numeric] = None, - symbol_keep_aspect: bool = False, - symbol_offset: Optional[Sequence] = None, - label_opts: Union[LabelOpts, dict, None] = None, - itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, - tooltip_opts: Union[TooltipOpts, dict, None] = None, - ): - self.opts: dict = { - "name": name, - "value": value, - "symbol": symbol, - "symbolSize": symbol_size, - "symbolRotate": symbol_rotate, - "symbolKeepAspect": symbol_keep_aspect, - "symbolOffset": symbol_offset, - "label": label_opts, - "itemStyle": itemstyle_opts, - "tooltip": tooltip_opts, - } - - -class SunburstItem(BasicOpts): - def __init__( - self, - value: Optional[Numeric] = None, - name: Optional[str] = None, - link: Optional[str] = None, - target: Optional[str] = "blank", - label_opts: Union[LabelOpts, dict, None] = None, - itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, - children: Optional[Sequence] = None, - ): - self.opts: dict = { - "value": value, - "name": name, - "link": link, - "target": target, - "label": label_opts, - "itemStyle": itemstyle_opts, - "children": children, - } - - -class ThemeRiverItem(BasicOpts): - def __init__( - self, - date: Optional[str] = None, - value: Optional[Numeric] = None, - name: Optional[str] = None, - ): - self.opts: dict = {"date": date, "value": value, "name": name} - - -class TreeItem(BasicOpts): - def __init__( - self, - name: Optional[str] = None, - value: Optional[Numeric] = None, - label_opts: Union[LabelOpts, dict, None] = None, - children: Optional[Sequence] = None, - ): - self.opts: dict = { - "name": name, - "value": value, - "children": children, - "label": label_opts, - } - - -# Chart Options -class GraphNode(BasicOpts): - def __init__( - self, - name: Optional[str] = None, - x: Optional[Numeric] = None, - y: Optional[Numeric] = None, - is_fixed: bool = False, - value: Union[str, Sequence, None] = None, - category: Optional[int] = None, - symbol: Optional[str] = None, - symbol_size: Union[Numeric, Sequence, None] = None, - label_opts: Union[LabelOpts, dict, None] = None, - ): - self.opts: dict = { - "name": name, - "x": x, - "y": y, - "fixed": is_fixed, - "value": value, - "category": category, - "symbol": symbol, - "symbolSize": symbol_size, - "label": label_opts, - } - - -class GraphLink(BasicOpts): - def __init__( - self, - source: Union[str, int, None] = None, - target: Union[str, int, None] = None, - value: Optional[Numeric] = None, - symbol: Union[str, Sequence, None] = None, - symbol_size: Union[Numeric, Sequence, None] = None, - linestyle_opts: Union[LineStyleOpts, dict, None] = None, - label_opts: Union[LabelOpts, dict, None] = None, - ): - self.opts: dict = { - "source": source, - "target": target, - "value": value, - "symbol": symbol, - "symbolSize": symbol_size, - "lineStyle": linestyle_opts, - "label": label_opts, - } - - -class GraphCategory(BasicOpts): - def __init__( - self, - name: Optional[str] = None, - symbol: Optional[str] = None, - symbol_size: Union[Numeric, Sequence, None] = None, - label_opts: Union[LabelOpts, dict, None] = None, - ): - self.opts: dict = { - "name": name, - "symbol": symbol, - "symbolSize": symbol_size, - "label": label_opts, - } - - -class BMapNavigationControlOpts(BasicOpts): - def __init__( - self, - position: Numeric = BMapType.ANCHOR_TOP_LEFT, - offset_width: Numeric = 10, - offset_height: Numeric = 10, - type_: Numeric = BMapType.NAVIGATION_CONTROL_LARGE, - is_show_zoom_info: bool = False, - is_enable_geo_location: bool = False, - ): - bmap_nav_config = json.dumps( - { - "anchor": position, - "offset": {"width": offset_width, "height": offset_height}, - "type": type_, - "showZoomInfo": is_show_zoom_info, - "enableGeolocation": is_enable_geo_location, - } - ) - - self.opts: dict = { - "functions": [ - "bmap.addControl(new BMap.NavigationControl({}));".format( - bmap_nav_config - ) - ] - } - - -class BMapOverviewMapControlOpts(BasicOpts): - def __init__( - self, - position: Numeric = BMapType.ANCHOR_BOTTOM_RIGHT, - offset_width: Numeric = 10, - offset_height: Numeric = 50, - is_open: bool = False, - ): - bmap_overview_config = json.dumps( - { - "anchor": position, - "offset": {"width": offset_width, "height": offset_height}, - "isOpen": is_open, - } - ) - - self.opts: dict = { - "functions": [ - "var overview = new BMap.OverviewMapControl({});".format( - bmap_overview_config - ), - "bmap.addControl(overview);", - ] - } - - -class BMapScaleControlOpts(BasicOpts): - def __init__( - self, - position: Numeric = BMapType.ANCHOR_BOTTOM_LEFT, - offset_width: Numeric = 80, - offset_height: Numeric = 21, - ): - bmap_scale_config = json.dumps( - { - "anchor": position, - "offset": {"width": offset_width, "height": offset_height}, - } - ) - - self.opts: dict = { - "functions": [ - "bmap.addControl(new BMap.ScaleControl({}));".format(bmap_scale_config) - ] - } - - -class BMapTypeControlOpts(BasicOpts): - def __init__( - self, - position: Numeric = BMapType.ANCHOR_TOP_RIGHT, - type_: Numeric = BMapType.MAPTYPE_CONTROL_HORIZONTAL, - ): - bmap_type_config = json.dumps({"anchor": position, "type": type_}) - - self.opts: dict = { - "functions": [ - "bmap.addControl(new BMap.MapTypeControl({}));".format(bmap_type_config) - ] - } - - -class BMapCopyrightTypeOpts(BasicOpts): +class BMapCopyrightTypeOpts(BasicOpts): def __init__( self, position: Numeric = BMapType.ANCHOR_BOTTOM_LEFT, @@ -632,6 +421,8 @@ def __init__( pos_x: Numeric = 0, pos_y: Numeric = 0, font: Optional[str] = None, + font_size: Optional[Numeric] = 0, + font_weight: Optional[str] = None, text_align: str = "left", text_vertical_align: Optional[str] = None, graphic_basicstyle_opts: Union[GraphicBasicStyleOpts, dict, None] = None, @@ -641,6 +432,8 @@ def __init__( "x": pos_x, "y": pos_y, "font": font, + "fontSize": font_size, + "fontWeight": font_weight, "textAlign": text_align, "textVerticalAlign": text_vertical_align, } @@ -657,7 +450,7 @@ def __init__( self, id_: Optional[str] = None, action: str = "merge", - position: [Sequence, Numeric, None] = None, + position: Union[Sequence, Numeric, None] = None, rotation: Union[Numeric, JSFunc, None] = 0, scale: Union[Sequence, Numeric, None] = None, origin: Union[Numeric, Sequence, None] = None, @@ -835,6 +628,7 @@ def __init__( class TreeMapLevelsOpts(BasicOpts): def __init__( self, + color: Union[str, Sequence] = None, color_alpha: Union[Numeric, Sequence] = None, color_saturation: Union[Numeric, Sequence] = None, color_mapping_by: str = "index", @@ -843,6 +637,7 @@ def __init__( upper_label_opts: Union[LabelOpts, dict, None] = None, ): self.opts: dict = { + "color": color, "colorAlpha": color_alpha, "colorSaturation": color_saturation, "colorMappingBy": color_mapping_by, @@ -1066,6 +861,30 @@ def __init__( } +class GlobeLayersOpts(BasicOpts): + def __init__( + self, + is_show: bool = True, + type_: str = "overlay", + name: Optional[str] = None, + blend_to: str = "albedo", + intensity: Numeric = 1, + shading: str = "lambert", + distance: Optional[Numeric] = None, + texture: Union[JSFunc, None] = None, + ): + self.opts: dict = { + "show": is_show, + "type": type_, + "name": name, + "blendTo": blend_to, + "intensity": intensity, + "shading": shading, + "distance": distance, + "texture": texture, + } + + class BarBackgroundStyleOpts(BasicOpts): def __init__( self, @@ -1073,7 +892,7 @@ def __init__( border_color: str = "#000", border_width: Numeric = 0, border_type: str = "solid", - bar_border_radius: Union[Numeric, Sequence] = 0, + border_radius: Union[Numeric, Sequence] = 0, shadow_blur: Optional[Numeric] = None, shadow_color: Optional[str] = None, shadow_offset_x: Numeric = 0, @@ -1085,7 +904,7 @@ def __init__( "borderColor": border_color, "borderWidth": border_width, "borderType": border_type, - "barBorderRadius": bar_border_radius, + "borderRadius": border_radius, "shadowBlur": shadow_blur, "shadowColor": shadow_color, "shadowOffsetX": shadow_offset_x, @@ -1113,6 +932,9 @@ def __init__( shadow_blur: Optional[Numeric] = 0, shadow_offset_x: Numeric = 0, shadow_offset_y: Numeric = 0, + overflow: Optional[str] = "none", + rich: Optional[dict] = None, + is_value_animation: bool = True, ): if offset_center is None: offset_center = [0, "-40%"] @@ -1133,6 +955,9 @@ def __init__( "shadowBlur": shadow_blur, "shadowOffsetX": shadow_offset_x, "shadowOffsetY": shadow_offset_y, + "overflow": overflow, + "rich": rich, + "valueAnimation": is_value_animation, } @@ -1145,7 +970,7 @@ def __init__( border_color: str = "transparent", offset_center: Sequence = None, formatter: Optional[JSFunc] = None, - color: str = "auto", + color: str = "#464646", font_style: str = "normal", font_weight: str = "normal", font_family: str = "sans-serif", @@ -1156,6 +981,9 @@ def __init__( shadow_blur: Optional[Numeric] = 0, shadow_offset_x: Numeric = 0, shadow_offset_y: Numeric = 0, + overflow: Optional[str] = "none", + rich: Optional[dict] = None, + is_value_animation: bool = True, ): if offset_center is None: offset_center = [0, "-40%"] @@ -1177,34 +1005,119 @@ def __init__( "shadowBlur": shadow_blur, "shadowOffsetX": shadow_offset_x, "shadowOffsetY": shadow_offset_y, + "overflow": overflow, + "rich": rich, + "valueAnimation": is_value_animation, } -class GaugePointerOpts(BasicOpts): +class GaugeProgressOpts(BasicOpts): def __init__( self, - is_show: bool = True, - length: Union[str, Numeric] = "80%", - width: Numeric = 8, + is_show: bool = False, + is_overlap: bool = True, + width: Numeric = 10, + is_round_cap: bool = False, + is_clip: bool = False, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, ): - self.opts: dict = {"show": is_show, "length": length, "width": width} + self.opts: dict = { + "show": is_show, + "overlap": is_overlap, + "width": width, + "roundCap": is_round_cap, + "clip": is_clip, + "itemStyle": itemstyle_opts, + } -class PieLabelLineOpts(BasicOpts): +class GaugePointerOpts(BasicOpts): def __init__( self, is_show: bool = True, - length: Numeric = None, - length_2: Numeric = None, - smooth: Union[bool, Numeric] = False, - linestyle_opts: Union[LineStyleOpts, dict, None] = None, + length: Union[str, Numeric] = "80%", + width: Numeric = 8, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, ): self.opts: dict = { "show": is_show, "length": length, - "length2": length_2, - "smooth": smooth, - "lineStyle": linestyle_opts, + "width": width, + "itemStyle": itemstyle_opts, + } + + +class GaugeAnchorOpts(BasicOpts): + def __init__( + self, + is_show: bool = True, + is_show_above: bool = False, + size: Numeric = 6, + icon: str = "circle", + offset_center: Optional[Sequence] = None, + is_keep_aspect: bool = False, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + ): + if offset_center is None: + offset_center = [0, 0] + self.opts: dict = { + "show": is_show, + "showAbove": is_show_above, + "size": size, + "icon": icon, + "offsetCenter": offset_center, + "keepAspect": is_keep_aspect, + "itemStyle": itemstyle_opts, + } + + +class PieLabelLineOpts(BasicOpts): + def __init__( + self, + is_show: bool = True, + is_show_above: bool = False, + length: Numeric = 15, + length_2: Numeric = 15, + smooth: Union[bool, Numeric] = False, + min_turn_angle: Numeric = 90, + linestyle_opts: Union[LineStyleOpts, dict, None] = None, + max_surface_angle: Numeric = 90, + ): + self.opts: dict = { + "show": is_show, + "showAbove": is_show_above, + "length": length, + "length2": length_2, + "smooth": smooth, + "minTurnAngle": min_turn_angle, + "lineStyle": linestyle_opts, + "maxSurfaceAngle": max_surface_angle, + } + + +class PieEmptyCircleStyle(BasicOpts): + def __init__( + self, + color: str = "lightgray", + border_color: str = "#000", + border_width: Numeric = 0, + border_type: str = "solid", + border_dash_offset: Numeric = 0, + border_cap: str = "butt", + border_join: str = "bevel", + border_miter_limit: Numeric = 10, + opacity: Numeric = 1, + ): + self.opts: dict = { + "color": color, + "borderColor": border_color, + "borderWidth": border_width, + "borderType": border_type, + "borderDashOffset": border_dash_offset, + "borderCap": border_cap, + "borderJoin": border_join, + "borderMiterLimit": border_miter_limit, + "opacity": opacity, } @@ -1275,3 +1188,588 @@ def __init__( "borderColor": border_color, "borderWidth": border_width, } + + +class TabChartGlobalOpts(BasicOpts): + def __init__( + self, + is_enable: bool = False, + tab_base_css: Optional[dict] = None, + tab_button_css: Optional[dict] = None, + tab_button_hover_css: Optional[dict] = None, + tab_button_active_css: Optional[dict] = None, + ): + self.opts: dict = { + "enable": is_enable, + "base": tab_base_css, + "button_base": tab_button_css, + "button_hover": tab_button_hover_css, + "button_active": tab_button_active_css, + } + + +class GraphGLNode(BasicOpts): + def __init__( + self, + name: Optional[str] = None, + x: Optional[Numeric] = None, + y: Optional[Numeric] = None, + value: Union[str, Numeric, Sequence, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + ): + self.opts: dict = { + "name": name, + "x": x, + "y": y, + "value": value, + "itemStyle": itemstyle_opts, + } + + +class GraphGLLink(BasicOpts): + def __init__( + self, + source: Union[str, int, None] = None, + target: Union[str, int, None] = None, + value: Optional[Numeric] = None, + linestyle_opts: Union[LineStyleOpts, dict, None] = None, + ): + self.opts: dict = { + "source": source, + "target": target, + "value": value, + "lineStyle": linestyle_opts, + } + + +class GeoRegionsOpts(BasicOpts): + def __init__( + self, + name: Optional[str] = None, + is_selected: bool = False, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + label_opts: Union[LabelOpts, dict, None] = None, + emphasis_itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + emphasis_label_opts: Union[LabelOpts, dict, None] = None, + select_itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + select_label_opts: Union[LabelOpts, dict, None] = None, + blur_itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + blur_label_opts: Union[LabelOpts, dict, None] = None, + tooltip_opts: Union[TooltipOpts, dict, None] = None, + is_silent: bool = False, + ): + self.opts: dict = { + "name": name, + "selected": is_selected, + "itemStyle": itemstyle_opts, + "label": label_opts, + "emphasis": { + "itemStyle": emphasis_itemstyle_opts, + "label": emphasis_label_opts, + }, + "select": { + "itemStyle": select_itemstyle_opts, + "label": select_label_opts, + }, + "blur": { + "itemStyle": blur_itemstyle_opts, + "label": blur_label_opts, + }, + "tooltip": tooltip_opts, + "silent": is_silent, + } + + +class SunburstLabelLineOpts(BasicOpts): + def __init__( + self, + is_show: Optional[bool] = None, + is_show_above: Optional[bool] = None, + length_2: Optional[Numeric] = None, + smooth: Union[bool, Numeric] = False, + min_turn_angle: Optional[Numeric] = None, + linestyle_opts: Union[LineStyleOpts, dict, None] = None, + ): + self.opts: dict = { + "show": is_show, + "showAbove": is_show_above, + "length2": length_2, + "smooth": smooth, + "minTurnAngle": min_turn_angle, + "lineStyle": linestyle_opts, + } + + +class SunburstLabelLayoutOpts(BasicOpts): + def __init__( + self, + is_hide_overlap: Optional[bool] = None, + is_move_overlap: Optional[bool] = None, + rotate: Optional[Numeric] = None, + width: Optional[Numeric] = None, + height: Optional[Numeric] = None, + align: Optional[str] = None, + vertical_align: Optional[str] = None, + font_size: Optional[Numeric] = None, + is_draggable: Optional[bool] = None, + ): + self.opts: dict = { + "hideOverlap": is_hide_overlap, + "moveOverlap": is_move_overlap, + "rotate": rotate, + "width": width, + "height": height, + "align": align, + "verticalAlign": vertical_align, + "fontSize": font_size, + "draggable": is_draggable, + } + + +class SunburstLevelOpts(BasicOpts): + def __init__( + self, + radius: Optional[Sequence] = None, + label_opts: Union[LabelOpts, dict, None] = None, + label_line_opts: Union[SunburstLabelLineOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + ): + self.opts: dict = { + "radius": radius, + "label": label_opts, + "labelLine": label_line_opts, + "itemStyle": itemstyle_opts, + } + + +# Data Item +class BarItem(BasicOpts): + def __init__( + self, + name: Union[int, str, None], + value: Numeric, + *, + group_id: Optional[str] = None, + label_opts: Union[LabelOpts, dict, None] = None, + is_show_label_line: Optional[bool] = None, + label_line_linestyle_opts: Union[LineStyleOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + tooltip_opts: Union[TooltipOpts, dict, None] = None, + ): + label_line = None + if is_show_label_line: + label_line = { + "show": is_show_label_line, + "lineStyle": label_line_linestyle_opts, + } + + self.opts: dict = { + "name": name, + "value": value, + "groupId": group_id, + "label": label_opts, + "labelLine": label_line, + "itemStyle": itemstyle_opts, + "tooltip": tooltip_opts, + } + + +class BoxplotItem(BasicOpts): + def __init__( + self, + name: Union[int, str], + value: Sequence, + *, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + tooltip_opts: Union[TooltipOpts, dict, None] = None, + ): + self.opts: dict = { + "name": name, + "value": value, + "itemStyle": itemstyle_opts, + "tooltip": tooltip_opts, + } + + +class CandleStickItem(BasicOpts): + def __init__( + self, + name: Union[str, int], + value: Sequence, + *, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + tooltip_opts: Union[TooltipOpts, dict, None] = None, + ): + self.opts: dict = { + "name": name, + "value": value, + "itemStyle": itemstyle_opts, + "tooltip": tooltip_opts, + } + + +class EffectScatterItem(BasicOpts): + def __init__( + self, + name: Union[str, Numeric], + value: Union[str, Numeric], + *, + symbol: Optional[str] = None, + symbol_size: Union[Sequence[Numeric], Numeric] = None, + symbol_rotate: Optional[Numeric] = None, + symbol_keep_aspect: bool = False, + symbol_offset: Optional[Sequence] = None, + label_opts: Union[LabelOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + tooltip_opts: Union[TooltipOpts, dict, None] = None, + ): + self.opts: dict = { + "name": name, + "value": value, + "symbol": symbol, + "symbolSize": symbol_size, + "symbolRotate": symbol_rotate, + "symbolKeepAspect": symbol_keep_aspect, + "symbolOffset": symbol_offset, + "label": label_opts, + "itemStyle": itemstyle_opts, + "tooltip": tooltip_opts, + } + + +class FunnelItem(BasicOpts): + def __init__( + self, + name: Union[str, int], + value: Union[Sequence, str, Numeric], + *, + is_show_label_line: Optional[bool] = None, + label_line_width: Optional[int] = None, + label_line_linestyle_opts: Union[LineStyleOpts, dict, None] = None, + label_opts: Union[LabelOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + tooltip_opts: Union[TooltipOpts, dict, None] = None, + ): + self.opts: dict = { + "name": name, + "value": value, + "labelLine": { + "show": is_show_label_line, + "length": label_line_width, + "lineStyle": label_line_linestyle_opts, + }, + "label": label_opts, + "itemStyle": itemstyle_opts, + "tooltip": tooltip_opts, + } + + +class LineItem(BasicOpts): + def __init__( + self, + name: Union[str, Numeric] = None, + value: Union[str, Numeric] = None, + *, + symbol: Optional[str] = "circle", + symbol_size: Numeric = 4, + symbol_rotate: Optional[Numeric] = None, + symbol_keep_aspect: bool = False, + symbol_offset: Optional[Sequence] = None, + label_opts: Union[LabelOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + tooltip_opts: Union[TooltipOpts, dict, None] = None, + ): + self.opts: dict = { + "name": name, + "value": value, + "symbol": symbol, + "symbolSize": symbol_size, + "symbolRotate": symbol_rotate, + "symbolKeepAspect": symbol_keep_aspect, + "symbolOffset": symbol_offset, + "label": label_opts, + "itemStyle": itemstyle_opts, + "tooltip": tooltip_opts, + } + + +class MapItem(BasicOpts): + def __init__( + self, + name: Optional[str] = None, + value: Union[Sequence, Numeric, str] = None, + group_id: Optional[str] = None, + is_selected: bool = False, + label_opts: Union[LabelOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + tooltip_opts: Union[TooltipOpts, dict, None] = None, + ): + self.opts: dict = { + "name": name, + "value": value, + "groupId": group_id, + "selected": is_selected, + "label": label_opts, + "itemStyle": itemstyle_opts, + "tooltip": tooltip_opts, + } + + +class GeoItem(BasicOpts): + def __init__( + self, + longitude: Numeric, + latitude: Numeric, + name: str, + value: Union[Sequence, Numeric, str] = None, + ): + self.opts: dict = { + "longitude": longitude, + "latitude": latitude, + "name": name, + "value": value, + } + + +class ParallelItem(BasicOpts): + def __init__( + self, + name: Optional[str] = None, + value: Optional[Sequence] = None, + linestyle_opts: Union[LineStyleOpts, dict, None] = None, + color: Union[str, dict] = "#000", + width: Numeric = 2, + type_: str = "solid", + dash_offset: Numeric = 0, + cap: str = "butt", + join: str = "bevel", + miter_limit: Optional[Numeric] = None, + opacity: Numeric = 0.45, + ): + self.opts: dict = { + "name": name, + "value": value, + "lineStyle": linestyle_opts, + "color": color, + "width": width, + "type": type_, + "dashOffset": dash_offset, + "cap": cap, + "join": join, + "miterLimit": miter_limit, + "opacity": opacity, + } + + +class PieItem(BasicOpts): + def __init__( + self, + name: Optional[str] = None, + value: Optional[Numeric] = None, + group_id: Optional[str] = None, + is_selected: bool = False, + label_opts: Union[LabelOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + tooltip_opts: Union[TooltipOpts, dict, None] = None, + label_line_opts: Union[PieLabelLineOpts, dict, None] = None, + ): + self.opts: dict = { + "name": name, + "value": value, + "groupId": group_id, + "selected": is_selected, + "label": label_opts, + "labelLine": label_line_opts, + "itemStyle": itemstyle_opts, + "tooltip": tooltip_opts, + } + + +class RadarItem(BasicOpts): + def __init__( + self, + name: Optional[str] = None, + value: Union[Sequence, Numeric, str] = None, + symbol: Optional[str] = None, + symbol_size: Union[Sequence[Numeric], Numeric] = None, + symbol_rotate: Optional[Numeric] = None, + symbol_keep_aspect: bool = False, + symbol_offset: Optional[Sequence] = None, + label_opts: Union[LabelOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + tooltip_opts: Union[TooltipOpts, dict, None] = None, + linestyle_opts: Union[LineStyleOpts, dict, None] = None, + areastyle_opts: Union[AreaStyleOpts, dict, None] = None, + ): + self.opts: dict = { + "name": name, + "value": value, + "symbol": symbol, + "symbolSize": symbol_size, + "symbolRotate": symbol_rotate, + "symbolKeepAspect": symbol_keep_aspect, + "symbolOffset": symbol_offset, + "label": label_opts, + "itemStyle": itemstyle_opts, + "tooltip": tooltip_opts, + "lineStyle": linestyle_opts, + "areaStyle": areastyle_opts, + } + + +class ScatterItem(BasicOpts): + def __init__( + self, + name: Union[str, Numeric] = None, + value: Union[str, Numeric, Sequence] = None, + symbol: Optional[str] = None, + symbol_size: Union[Sequence[Numeric], Numeric] = None, + symbol_rotate: Optional[Numeric] = None, + symbol_keep_aspect: bool = False, + symbol_offset: Optional[Sequence] = None, + label_opts: Union[LabelOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + tooltip_opts: Union[TooltipOpts, dict, None] = None, + ): + self.opts: dict = { + "name": name, + "value": value, + "symbol": symbol, + "symbolSize": symbol_size, + "symbolRotate": symbol_rotate, + "symbolKeepAspect": symbol_keep_aspect, + "symbolOffset": symbol_offset, + "label": label_opts, + "itemStyle": itemstyle_opts, + "tooltip": tooltip_opts, + } + + +class SunburstItem(BasicOpts): + def __init__( + self, + value: Optional[Numeric] = None, + name: Optional[str] = None, + link: Optional[str] = None, + target: Optional[str] = "blank", + label_opts: Union[LabelOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + children: Optional[Sequence] = None, + ): + self.opts: dict = { + "value": value, + "name": name, + "link": link, + "target": target, + "label": label_opts, + "itemStyle": itemstyle_opts, + "children": children, + } + + +class ThemeRiverItem(BasicOpts): + def __init__( + self, + date: Optional[str] = None, + value: Optional[Numeric] = None, + name: Optional[str] = None, + ): + self.opts: dict = {"date": date, "value": value, "name": name} + + +class TreeItem(BasicOpts): + def __init__( + self, + name: Optional[str] = None, + value: Optional[Numeric] = None, + label_opts: Union[LabelOpts, dict, None] = None, + children: Optional[Sequence] = None, + ): + self.opts: dict = { + "name": name, + "value": value, + "children": children, + "label": label_opts, + } + + +class CustomBarRangeItemPayloadOpts(BasicOpts): + def __init__( + self, + bar_width: Union[Numeric, str, None] = None, + border_radius: Optional[Numeric] = None, + margin: Optional[Numeric] = None, + ): + self.opts: dict = { + "barWidth": bar_width, + "borderRadius": border_radius, + "margin": margin, + } + + +class CustomContourItemPayloadOpts(BasicOpts): + def __init__( + self, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + linestyle_opts: Union[LineStyleOpts, dict, None] = None, + bandwidth: Optional[Numeric] = None, + ): + self.opts: dict = { + "itemStyle": itemstyle_opts, + "lineStyle": linestyle_opts, + "bandwidth": bandwidth, + } + + +class CustomLineRangeItemPayloadOpts(BasicOpts): + def __init__( + self, + linestyle_opts: Union[LineStyleOpts, dict, None] = None, + areastyle_opts: Union[AreaStyleOpts, dict, None] = None, + ): + self.opts: dict = { + "areaStyle": areastyle_opts, + "lineStyle": linestyle_opts, + } + + +class CustomSegmentedDoughnutItemPayloadOpts(BasicOpts): + def __init__( + self, + center: Optional[Sequence] = None, + radius: Optional[Sequence] = None, + segment_count: Optional[Numeric] = None, + label_opts: Union[LabelOpts, dict, None] = None, + ): + self.opts: dict = { + "center": center, + "radius": radius, + "segmentCount": segment_count, + "label": label_opts, + } + + +class CustomStageItemPayloadOpts(BasicOpts): + def __init__( + self, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + ): + self.opts: dict = { + "itemStyle": itemstyle_opts, + } + + +class CustomViolinItemPayloadOpts(BasicOpts): + def __init__( + self, + symbol_size: Optional[Numeric] = None, + area_opacity: Optional[Numeric] = None, + bandwidth_scale: Optional[Numeric] = None, + bin_count: Optional[Numeric] = None, + ): + self.opts: dict = { + "symbolSize": symbol_size, + "areaOpacity": area_opacity, + "bandWidthScale": bandwidth_scale, + "binCount": bin_count, + } diff --git a/pyecharts/options/global_options.py b/pyecharts/options/global_options.py index 0cf8015f8..aa9eed2be 100644 --- a/pyecharts/options/global_options.py +++ b/pyecharts/options/global_options.py @@ -1,6 +1,8 @@ from ..globals import CurrentConfig, RenderType, ThemeType from ..options.series_options import ( BasicOpts, + AnimationOpts, + AreaStyleOpts, ItemStyleOpts, JSFunc, LabelOpts, @@ -17,27 +19,111 @@ ) -class AnimationOpts(BasicOpts): +class AriaLabelOpts(BasicOpts): def __init__( self, - animation: bool = True, - animation_threshold: Numeric = 2000, - animation_duration: Union[Numeric, JSFunc] = 1000, - animation_easing: Union[str] = "cubicOut", - animation_delay: Union[Numeric, JSFunc] = 0, - animation_duration_update: Union[Numeric, JSFunc] = 300, - animation_easing_update: Union[Numeric] = "cubicOut", - animation_delay_update: Union[Numeric, JSFunc] = 0, + is_enable: bool = True, + description: Optional[str] = None, + general_with_title: str = "这是一个关于“{title}”的图表。", + general_without_title: str = "这是一个图表,", + series_max_count: int = 10, + series_single_prefix: str = "", + series_single_with_name: str = "图表类型是{seriesType},表示{seriesName}。", + series_single_without_name: str = "图表类型是{seriesType}。", + series_multiple_prefix: str = "它由{seriesCount}个图表系列组成。", + series_multiple_with_name: str = "图表类型是{seriesType},表示{seriesName}。", + series_multiple_without_name: str = "图表类型是{seriesType}。", + series_multiple_separator_middle: str = ";", + series_multiple_separator_end: str = "。", + data_max_count: int = 10, + data_all_data: str = "其数据是——", + data_partial_data: str = "其中,前{displayCnt}项是——", + data_with_name: str = "{name}的数据是{value}", + data_without_name: str = "{value}", + data_separator_middle: str = ",", + data_separator_end: str = "", ): self.opts: dict = { - "animation": animation, - "animationThreshold": animation_threshold, - "animationDuration": animation_duration, - "animationEasing": animation_easing, - "animationDelay": animation_delay, - "animationDurationUpdate": animation_duration_update, - "animationEasingUpdate": animation_easing_update, - "animationDelayUpdate": animation_delay_update, + "enabled": is_enable, + "description": description, + "general": { + "withTitle": general_with_title, + "withoutTitle": general_without_title, + }, + "series": { + "maxCount": series_max_count, + "single": { + "prefix": series_single_prefix, + "withName": series_single_with_name, + "withoutName": series_single_without_name, + }, + "multiple": { + "prefix": series_multiple_prefix, + "withName": series_multiple_with_name, + "withoutName": series_multiple_without_name, + "separator": { + "middle": series_multiple_separator_middle, + "end": series_multiple_separator_end, + }, + }, + }, + "data": { + "maxCount": data_max_count, + "allData": data_all_data, + "partialData": data_partial_data, + "withName": data_with_name, + "withoutName": data_without_name, + "separator": { + "middle": data_separator_middle, + "end": data_separator_end, + }, + }, + } + + +class AriaDecalOpts(BasicOpts): + def __init__( + self, + is_show: bool = False, + decals_symbol: Union[str, Sequence] = "rect", + decals_symbol_size: Numeric = 1, + decals_symbol_keep_aspect: bool = True, + decals_color: str = "rgba(0, 0, 0, 0.2)", + decals_background_color: Optional[str] = None, + decals_dash_array_x: Union[Numeric, Sequence] = 5, + decals_dash_array_y: Union[Numeric, Sequence] = 5, + decals_rotation: Numeric = 0, + decals_max_tile_width: Numeric = 512, + decals_max_tile_height: Numeric = 512, + ): + self.opts: dict = { + "show": is_show, + "decals": { + "symbol": decals_symbol, + "symbolSize": decals_symbol_size, + "symbolKeepAspect": decals_symbol_keep_aspect, + "color": decals_color, + "backgroundColor": decals_background_color, + "dashArrayX": decals_dash_array_x, + "dashArrayY": decals_dash_array_y, + "rotation": decals_rotation, + "maxTileWidth": decals_max_tile_width, + "maxTileHeight": decals_max_tile_height, + }, + } + + +class AriaOpts(BasicOpts): + def __init__( + self, + is_enable: bool = False, + aria_label_opts: Optional[AriaLabelOpts] = None, + aria_decal_opts: Optional[AriaDecalOpts] = None, + ): + self.opts: dict = { + "enabled": is_enable, + "label": aria_label_opts, + "decal": aria_decal_opts, } @@ -46,24 +132,91 @@ def __init__( self, width: str = "900px", height: str = "500px", + is_horizontal_center: bool = False, chart_id: Optional[str] = None, renderer: str = RenderType.CANVAS, page_title: str = CurrentConfig.PAGE_TITLE, theme: str = ThemeType.WHITE, bg_color: Union[str, dict] = None, + is_fill_bg_color: bool = False, js_host: str = "", animation_opts: Union[AnimationOpts, dict] = AnimationOpts(), + aria_opts: Union[AriaOpts, dict] = AriaOpts(), ): self.opts: dict = { "width": width, "height": height, + "is_horizontal_center": is_horizontal_center, "chart_id": chart_id, "renderer": renderer, "page_title": page_title, "theme": theme, "bg_color": bg_color, + "fill_bg": is_fill_bg_color, "js_host": js_host, "animationOpts": animation_opts, + "ariaOpts": aria_opts, + } + + +class RenderOpts(BasicOpts): + def __init__(self, is_embed_js: bool = False): + self.opts: dict = { + "embed_js": is_embed_js, + } + + +class TooltipOpts(BasicOpts): + def __init__( + self, + is_show: bool = True, + trigger: str = "item", + trigger_on: str = "mousemove|click", + axis_pointer_type: str = "line", + is_show_content: bool = True, + is_always_show_content: bool = False, + show_delay: Numeric = 0, + hide_delay: Numeric = 100, + is_enterable: bool = False, + is_confine: bool = False, + is_append_to_body: bool = False, + transition_duration: Numeric = 0.4, + is_display_transition: bool = True, + position: Union[str, Sequence, JSFunc] = None, + formatter: Optional[JSFunc] = None, + value_formatter: Optional[JSFunc] = None, + background_color: Optional[str] = None, + border_color: Optional[str] = None, + border_width: Numeric = 0, + padding: Union[Numeric, Sequence[Numeric]] = 5, + textstyle_opts: Optional[TextStyleOpts] = TextStyleOpts(font_size=14), + extra_css_text: Optional[str] = None, + order: str = "seriesAsc", + ): + self.opts: dict = { + "show": is_show, + "trigger": trigger, + "triggerOn": trigger_on, + "axisPointer": {"type": axis_pointer_type}, + "showContent": is_show_content, + "alwaysShowContent": is_always_show_content, + "showDelay": show_delay, + "hideDelay": hide_delay, + "enterable": is_enterable, + "confine": is_confine, + "appendToBody": is_append_to_body, + "transitionDuration": transition_duration, + "displayTransition": is_display_transition, + "position": position, + "formatter": formatter, + "valueFormatter": value_formatter, + "textStyle": textstyle_opts, + "backgroundColor": background_color, + "borderColor": border_color, + "borderWidth": border_width, + "padding": padding, + "extraCssText": extra_css_text, + "order": order, } @@ -76,7 +229,7 @@ def __init__( connected_background_color: str = "#fff", exclude_components: Optional[Sequence[str]] = None, is_show: bool = True, - title: str = "保存为图片", + title: Optional[str] = None, icon: Optional[JSFunc] = None, pixel_ratio: Numeric = 1, ): @@ -95,7 +248,10 @@ def __init__( class ToolBoxFeatureRestoreOpts(BasicOpts): def __init__( - self, is_show: bool = True, title: str = "还原", icon: Optional[JSFunc] = None + self, + is_show: bool = True, + title: Optional[str] = None, + icon: Optional[JSFunc] = None ): self.opts: dict = {"show": is_show, "title": title, "icon": icon} @@ -104,7 +260,7 @@ class ToolBoxFeatureDataViewOpts(BasicOpts): def __init__( self, is_show: bool = True, - title: str = "数据视图", + title: Optional[str] = None, icon: Optional[JSFunc] = None, is_read_only: bool = False, option_to_content: Optional[JSFunc] = None, @@ -117,9 +273,6 @@ def __init__( button_color: str = "#c23531", button_text_color: str = "#fff", ): - if lang is None: - lang = ["数据视图", "关闭", "刷新"] - self.opts: dict = { "show": is_show, "title": title, @@ -141,12 +294,12 @@ class ToolBoxFeatureDataZoomOpts(BasicOpts): def __init__( self, is_show: bool = True, - zoom_title: str = "区域缩放", - back_title: str = "区域缩放还原", + zoom_title: Optional[str] = None, + back_title: Optional[str] = None, zoom_icon: Optional[JSFunc] = None, back_icon: Optional[JSFunc] = None, - xaxis_index: Union[Numeric, Sequence, bool] = False, - yaxis_index: Union[Numeric, Sequence, bool] = False, + xaxis_index: Union[Numeric, Sequence, bool] = None, + yaxis_index: Union[Numeric, Sequence, bool] = None, filter_mode: str = "filter", ): self.opts: dict = { @@ -164,10 +317,10 @@ def __init__( self, is_show: bool = True, type_: Optional[Sequence] = None, - line_title: str = "切换为折线图", - bar_title: str = "切换为柱状图", - stack_title: str = "切换为堆叠", - tiled_title: str = "切换为平铺", + line_title: Optional[str] = None, + bar_title: Optional[str] = None, + stack_title: Optional[str] = None, + tiled_title: Optional[str] = None, line_icon: Optional[JSFunc] = None, bar_icon: Optional[JSFunc] = None, stack_icon: Optional[JSFunc] = None, @@ -204,12 +357,12 @@ def __init__( line_y_icon: Optional[JSFunc] = None, keep_icon: Optional[JSFunc] = None, clear_icon: Optional[JSFunc] = None, - rect_title: str = "矩形选择", - polygon_title: str = "圈选", - line_x_title: str = "横向选择", - line_y_title: str = "纵向选择", - keep_title: str = "保持选择", - clear_title: str = "清除选择", + rect_title: Optional[str] = None, + polygon_title: Optional[str] = None, + line_x_title: Optional[str] = None, + line_y_title: Optional[str] = None, + keep_title: Optional[str] = None, + clear_title: Optional[str] = None, ): self.opts: dict = { "type": type_, @@ -248,7 +401,7 @@ def __init__( magic_type: Union[ ToolBoxFeatureMagicTypeOpts, dict ] = ToolBoxFeatureMagicTypeOpts(), - brush: Union[ToolBoxFeatureBrushOpts, dict] = ToolBoxFeatureBrushOpts(), + brush: Union[ToolBoxFeatureBrushOpts, dict] = None, ): self.opts: dict = { "saveAsImage": save_as_image, @@ -272,6 +425,18 @@ def __init__( pos_top: Optional[str] = None, pos_bottom: Optional[str] = None, feature: Union[ToolBoxFeatureOpts, dict] = ToolBoxFeatureOpts(), + z_level: Optional[Numeric] = None, + z: Optional[Numeric] = None, + width: Optional[str] = None, + height: Optional[str] = None, + coordinate_system: Optional[str] = None, + coordinate_system_usage: Optional[str] = None, + coord: Optional[Union[Sequence, Numeric, str]] = None, + calendar_index: Optional[Numeric] = None, + calendar_id: Optional[Numeric] = None, + matrix_index: Optional[Numeric] = None, + matrix_id: Optional[Numeric] = None, + tooltip_opts: Union[TooltipOpts, dict, None] = None, ): self.opts: dict = { "show": is_show, @@ -283,6 +448,18 @@ def __init__( "top": pos_top, "bottom": pos_bottom, "feature": feature, + "zlevel": z_level, + "z": z, + "width": width, + "height": height, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, + "tooltip": tooltip_opts, } @@ -302,7 +479,9 @@ def __init__( throttle_type: str = "fixRate", throttle_delay: Numeric = 0, remove_on_click: bool = True, - out_of_brush: dict = None, + in_brush: Optional[dict] = None, + out_of_brush: Optional[dict] = None, + z: Numeric = 10000, ): if tool_box is None: tool_box = ["rect", "polygon", "keep", "clear"] @@ -328,30 +507,44 @@ def __init__( "throttleType": throttle_type, "throttleDelay": throttle_delay, "removeOnClick": remove_on_click, + "inBrush": in_brush, "outOfBrush": out_of_brush, + "z": z, } class TitleOpts(BasicOpts): def __init__( self, + is_show: bool = True, title: Optional[str] = None, title_link: Optional[str] = None, - title_target: Optional[str] = None, + title_target: Optional[str] = "blank", subtitle: Optional[str] = None, subtitle_link: Optional[str] = None, - subtitle_target: Optional[str] = None, - pos_left: Optional[str] = None, - pos_right: Optional[str] = None, - pos_top: Optional[str] = None, - pos_bottom: Optional[str] = None, + subtitle_target: Optional[str] = "blank", + pos_left: Union[str, Numeric] = None, + pos_right: Union[str, Numeric] = None, + pos_top: Union[str, Numeric] = None, + pos_bottom: Union[str, Numeric] = None, + coordinate_system: Optional[str] = None, + coordinate_system_usage: Optional[str] = None, + coord: Optional[Union[Sequence, Numeric, str]] = None, + calendar_index: Optional[Numeric] = None, + calendar_id: Optional[Numeric] = None, + matrix_index: Optional[Numeric] = None, + matrix_id: Optional[Numeric] = None, padding: Union[Sequence, Numeric] = 5, item_gap: Numeric = 10, + text_align: str = "auto", + text_vertical_align: str = "auto", + is_trigger_event: bool = False, title_textstyle_opts: Union[TextStyleOpts, dict, None] = None, subtitle_textstyle_opts: Union[TextStyleOpts, dict, None] = None, ): self.opts: Sequence = [ { + "show": is_show, "text": title, "link": title_link, "target": title_target, @@ -362,8 +555,18 @@ def __init__( "right": pos_right, "top": pos_top, "bottom": pos_bottom, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, "padding": padding, "itemGap": item_gap, + "textAlign": text_align, + "textVerticalAlign": text_vertical_align, + "triggerEvent": is_trigger_event, "textStyle": title_textstyle_opts, "subtextStyle": subtitle_textstyle_opts, } @@ -375,51 +578,126 @@ def __init__( self, is_show: bool = True, type_: str = "slider", + is_disabled: bool = False, is_realtime: bool = True, + is_show_detail: bool = True, + is_show_data_shadow: bool = True, range_start: Union[Numeric, None] = 20, range_end: Union[Numeric, None] = 80, start_value: Union[int, str, None] = None, end_value: Union[int, str, None] = None, + min_span: Union[int, None] = None, + max_span: Union[int, None] = None, + min_value_span: Union[int, str, None] = None, + max_value_span: Union[int, str, None] = None, orient: str = "horizontal", xaxis_index: Union[int, Sequence[int], None] = None, yaxis_index: Union[int, Sequence[int], None] = None, + radius_axis_index: Union[int, Sequence[int], None] = None, + angle_axis_index: Union[int, Sequence[int], None] = None, is_zoom_lock: bool = False, - pos_left: Optional[str] = None, - pos_right: Optional[str] = None, - pos_top: Optional[str] = None, - pos_bottom: Optional[str] = None, + throttle: Optional[int] = None, + range_mode: Optional[Sequence] = None, + pos_left: Union[Numeric, str] = None, + pos_right: Union[Numeric, str] = None, + pos_top: Union[Numeric, str] = None, + pos_bottom: Union[Numeric, str] = None, + width: Union[Numeric, str] = None, + height: Union[Numeric, str] = None, filter_mode: str = "filter", + is_zoom_on_mouse_wheel: bool = True, + is_move_on_mouse_move: bool = True, + is_move_on_mouse_wheel: bool = True, + is_prevent_default_mouse_move: bool = True, + coordinate_system: Optional[str] = None, + coordinate_system_usage: Optional[str] = None, + coord: Optional[Union[Sequence, Numeric, str]] = None, + calendar_index: Optional[Numeric] = None, + calendar_id: Optional[Numeric] = None, + matrix_index: Optional[Numeric] = None, + matrix_id: Optional[Numeric] = None, ): self.opts: dict = { "show": is_show, "type": type_, + "showDetail": is_show_detail, + "showDataShadow": is_show_data_shadow, "realtime": is_realtime, "startValue": start_value, "endValue": end_value, "start": range_start, "end": range_end, + "minSpan": min_span, + "maxSpan": max_span, + "minValueSpan": min_value_span, + "maxValueSpan": max_value_span, "orient": orient, "xAxisIndex": xaxis_index, "yAxisIndex": yaxis_index, + "radiusAxisIndex": radius_axis_index, + "angleAxisIndex": angle_axis_index, "zoomLock": is_zoom_lock, + "throttle": throttle, + "rangeMode": range_mode, "left": pos_left, "right": pos_right, "top": pos_top, "bottom": pos_bottom, "filterMode": filter_mode, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, } + # inside have some different configurations. + if type_ == "inside": + self.opts.update({ + "disabled": is_disabled, + "zoomOnMouseWheel": is_zoom_on_mouse_wheel, + "moveOnMouseMove": is_move_on_mouse_move, + "moveOnMouseWheel": is_move_on_mouse_wheel, + "preventDefaultMouseMove": is_prevent_default_mouse_move, + }) + + # slider have some different configurations. + if type_ == "slider": + self.opts.update({ + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, + "width": width, + "height": height, + }) + class LegendOpts(BasicOpts): def __init__( self, type_: Optional[str] = None, selected_mode: Union[str, bool, None] = None, + selected_map: Optional[dict] = None, is_show: bool = True, pos_left: Union[str, Numeric, None] = None, pos_right: Union[str, Numeric, None] = None, pos_top: Union[str, Numeric, None] = None, pos_bottom: Union[str, Numeric, None] = None, + width: Union[str, Numeric, None] = None, + height: Union[str, Numeric, None] = None, + coordinate_system: Optional[str] = None, + coordinate_system_usage: Optional[str] = None, + coord: Optional[Union[Sequence, Numeric, str]] = None, + calendar_index: Optional[Numeric] = None, + calendar_id: Optional[Numeric] = None, + matrix_index: Optional[Numeric] = None, + matrix_id: Optional[Numeric] = None, orient: Optional[str] = None, align: Optional[str] = None, padding: int = 5, @@ -429,15 +707,45 @@ def __init__( inactive_color: Optional[str] = None, textstyle_opts: Union[TextStyleOpts, dict, None] = None, legend_icon: Optional[str] = None, + background_color: Optional[str] = "transparent", + border_color: Optional[str] = "#ccc", + border_width: Optional[int] = None, + border_radius: Union[int, Sequence] = 0, + page_button_item_gap: int = 5, + page_button_gap: Optional[int] = None, + page_button_position: str = "end", + page_formatter: JSFunc = "{current}/{total}", + page_icon: Optional[str] = None, + page_icon_color: str = "#2f4554", + page_icon_inactive_color: str = "#aaa", + page_icon_size: Union[int, Sequence] = 15, + is_page_animation: Optional[bool] = None, + page_animation_duration_update: int = 800, + selector: Union[bool, Sequence] = False, + selector_label: Union[LabelOpts, dict, None] = None, + selector_position: str = "auto", + selector_item_gap: int = 7, + selector_button_gap: int = 10, + is_trigger_event: bool = False, ): self.opts: dict = { "type": type_, "selectedMode": selected_mode, + "selected": selected_map, "show": is_show, "left": pos_left, "right": pos_right, "top": pos_top, "bottom": pos_bottom, + "width": width, + "height": height, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, "orient": orient, "align": align, "padding": padding, @@ -447,6 +755,26 @@ def __init__( "inactiveColor": inactive_color, "textStyle": textstyle_opts, "icon": legend_icon, + "backgroundColor": background_color, + "borderColor": border_color, + "borderWidth": border_width, + "borderRadius": border_radius, + "pageButtonItemGap": page_button_item_gap, + "pageButtonGap": page_button_gap, + "pageButtonPosition": page_button_position, + "pageFormatter": page_formatter, + "pageIcon": page_icon, + "pageIconColor": page_icon_color, + "pageIconInactiveColor": page_icon_inactive_color, + "pageIconSize": page_icon_size, + "animation": is_page_animation, + "animationDurationUpdate": page_animation_duration_update, + "selector": selector, + "selectorLabel": selector_label, + "selectorPosition": selector_position, + "selectorItemGap": selector_item_gap, + "selectorButtonGap": selector_button_gap, + "triggerEvent": is_trigger_event, } @@ -457,29 +785,40 @@ def __init__( type_: str = "color", min_: Numeric = 0, max_: Numeric = 100, + range_: Sequence[Numeric] = None, range_text: Optional[Sequence] = None, range_color: Optional[Sequence[str]] = None, range_size: Optional[Sequence[int]] = None, - range_opacity: Optional[Numeric] = None, + range_opacity: Union[Numeric, Sequence[Numeric]] = None, orient: str = "vertical", - pos_left: Optional[str] = None, - pos_right: Optional[str] = None, - pos_top: Optional[str] = None, - pos_bottom: Optional[str] = None, + pos_left: Union[str, Numeric] = None, + pos_right: Union[str, Numeric] = None, + pos_top: Union[str, Numeric] = None, + pos_bottom: Union[str, Numeric] = None, + padding: Union[int, Sequence[int]] = 5, split_number: int = 5, series_index: Union[Numeric, Sequence, None] = None, + is_hover_link: bool = True, dimension: Optional[Numeric] = None, is_calculable: bool = True, is_piecewise: bool = False, is_inverse: bool = False, precision: Optional[int] = None, pieces: Optional[Sequence] = None, - out_of_range: Optional[Sequence] = None, + categories: Optional[Sequence] = None, + out_of_range: Optional[dict] = None, item_width: int = 0, item_height: int = 0, background_color: Optional[str] = None, border_color: Optional[str] = None, border_width: int = 0, + coordinate_system: Optional[str] = None, + coordinate_system_usage: Optional[str] = None, + coord: Optional[Union[Sequence, Numeric, str]] = None, + calendar_index: Optional[Numeric] = None, + calendar_id: Optional[Numeric] = None, + matrix_index: Optional[Numeric] = None, + matrix_id: Optional[Numeric] = None, textstyle_opts: Union[TextStyleOpts, dict, None] = None, ): _inrange_op: dict = {} @@ -493,6 +832,14 @@ def __init__( _inrange_op.update(opacity=range_opacity) _visual_typ = "piecewise" if is_piecewise else "continuous" + if type_ in ["piecewise", "continuous"] and ( + range_color or range_size or range_opacity, + ): + _inrange_op.update( + color=range_color, + symbolSize=range_size, + opacity=range_opacity, + ) if is_piecewise and item_width == 0 and item_height == 0: item_width, item_height = 20, 14 @@ -506,18 +853,21 @@ def __init__( "max": max_, "text": range_text, "textStyle": textstyle_opts, - "inRange": _inrange_op, + "range": range_, + "inRange": _inrange_op if _inrange_op else None, "calculable": is_calculable, "inverse": is_inverse, "precision": precision, "splitNumber": split_number, "dimension": dimension, "seriesIndex": series_index, + "hoverLink": is_hover_link, "orient": orient, "left": pos_left, "top": pos_top, "bottom": pos_bottom, "right": pos_right, + "padding": padding, "showLabel": True, "itemWidth": item_width, "itemHeight": item_height, @@ -525,47 +875,16 @@ def __init__( "backgroundColor": background_color, "borderColor": border_color, "borderWidth": border_width, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, } if is_piecewise: - self.opts.update(pieces=pieces) - - -class TooltipOpts(BasicOpts): - def __init__( - self, - is_show: bool = True, - trigger: str = "item", - trigger_on: str = "mousemove|click", - axis_pointer_type: str = "line", - is_show_content: bool = True, - is_always_show_content: bool = False, - show_delay: Numeric = 0, - hide_delay: Numeric = 100, - position: Union[str, Sequence, JSFunc] = None, - formatter: Optional[JSFunc] = None, - background_color: Optional[str] = None, - border_color: Optional[str] = None, - border_width: Numeric = 0, - padding: Numeric = 5, - textstyle_opts: TextStyleOpts = TextStyleOpts(font_size=14), - ): - self.opts: dict = { - "show": is_show, - "trigger": trigger, - "triggerOn": trigger_on, - "axisPointer": {"type": axis_pointer_type}, - "showContent": is_show_content, - "alwaysShowContent": is_always_show_content, - "showDelay": show_delay, - "hideDelay": hide_delay, - "position": position, - "formatter": formatter, - "textStyle": textstyle_opts, - "backgroundColor": background_color, - "borderColor": border_color, - "borderWidth": border_width, - "padding": padding, - } + self.opts.update(pieces=pieces, categories=categories) class AxisLineOpts(BasicOpts): @@ -610,15 +929,69 @@ def __init__( is_show: bool = False, link: Sequence[dict] = None, type_: str = "line", + is_snap: Optional[bool] = None, + is_trigger_tooltip: bool = True, + trigger_on: str = "mousemove|click", label: Union[LabelOpts, dict, None] = None, linestyle_opts: Union[LineStyleOpts, dict, None] = None, ): self.opts: dict = { "show": is_show, "type": type_, + "snap": is_snap, "link": link, "label": label, "lineStyle": linestyle_opts, + "triggerTooltip": is_trigger_tooltip, + "triggerOn": trigger_on, + } + + +class AxisBreakOpts(BasicOpts): + def __init__( + self, + start: Union[Numeric, str] = None, + end: Union[Numeric, str] = None, + gap: Union[Numeric, str] = None, + is_expanded: Optional[bool] = None, + ): + self.opts: dict = { + "start": start, + "end": end, + "gap": gap, + "isExpanded": is_expanded, + } + + +class AxisBreakAreaOpts(BasicOpts): + def __init__( + self, + is_show: Optional[bool] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + zigzag_amplitude: Optional[Numeric] = None, + zigzag_min_span: Optional[Numeric] = None, + zigzag_max_span: Optional[Numeric] = None, + zigzag_z: Optional[Numeric] = None, + is_expand_onclick: Optional[bool] = None, + ): + self.opts: dict = { + "show": is_show, + "itemStyle": itemstyle_opts, + "zigzagAmplitude": zigzag_amplitude, + "zigzagMinSpan": zigzag_min_span, + "zigzagMaxSpan": zigzag_max_span, + "zigzagZ": zigzag_z, + "expandOnClick": is_expand_onclick, + } + + +class AxisBreakLabelLayoutOpts(BasicOpts): + def __init__( + self, + is_move_overlap: Optional[bool] = None, + ): + self.opts: dict = { + "moveOverlap": is_move_overlap, } @@ -633,25 +1006,42 @@ def __init__( name_location: str = "end", name_gap: Numeric = 15, name_rotate: Optional[Numeric] = None, + name_truncate_max_width: Optional[Numeric] = None, + name_truncate_ellipsis: Optional[str] = None, + is_name_move_overlap: bool = True, interval: Optional[Numeric] = None, - grid_index: Numeric = 0, + grid_index: Optional[Numeric] = None, + grid_id: Optional[Numeric] = None, position: Optional[str] = None, offset: Numeric = 0, split_number: Numeric = 5, boundary_gap: Union[str, bool, None] = None, - min_: Union[Numeric, str, None] = None, - max_: Union[Numeric, str, None] = None, + min_: Union[Numeric, JSFunc, None] = None, + max_: Union[Numeric, JSFunc, None] = None, min_interval: Numeric = 0, max_interval: Optional[Numeric] = None, + log_base: Optional[Numeric] = None, + start_value: Optional[Numeric] = None, + is_silent: bool = False, + is_trigger_event: bool = False, + jitter: Optional[Numeric] = None, + is_jitter_overlap: Optional[bool] = None, + jitter_margin: Optional[Numeric] = None, + axisbreaks_opts: Sequence[Union[AxisBreakOpts, dict, None]] = None, + axisbreak_area_opts: Union[AxisBreakAreaOpts, dict, None] = None, + axisbreak_label_layout_opts: Union[ + AxisBreakLabelLayoutOpts, dict, None, + ] = None, axisline_opts: Union[AxisLineOpts, dict, None] = None, axistick_opts: Union[AxisTickOpts, dict, None] = None, axislabel_opts: Union[LabelOpts, dict, None] = None, axispointer_opts: Union[AxisPointerOpts, dict, None] = None, name_textstyle_opts: Union[TextStyleOpts, dict, None] = None, splitarea_opts: Union[SplitAreaOpts, dict, None] = None, - splitline_opts: Union[SplitLineOpts, dict] = SplitLineOpts(), + splitline_opts: Union[SplitLineOpts, dict] = SplitLineOpts(is_show=True), minor_tick_opts: Union[MinorTickOpts, dict, None] = None, minor_split_line_opts: Union[MinorSplitLineOpts, dict, None] = None, + animation_opts: Union[AnimationOpts, dict] = AnimationOpts(), ): self.opts: dict = { "type": type_, @@ -661,9 +1051,15 @@ def __init__( "nameLocation": name_location, "nameGap": name_gap, "nameRotate": name_rotate, + "nameTruncate": { + "maxWidth": name_truncate_max_width, + "ellipsis": name_truncate_ellipsis, + }, + "nameMoveOverlap": is_name_move_overlap, "interval": interval, "nameTextStyle": name_textstyle_opts, "gridIndex": grid_index, + "gridId": grid_id, "axisLine": axisline_opts, "axisTick": axistick_opts, "axisLabel": axislabel_opts, @@ -677,12 +1073,45 @@ def __init__( "max": max_, "minInterval": min_interval, "maxInterval": max_interval, + "logBase": log_base, + "startValue": start_value, + "silent": is_silent, + "triggerEvent": is_trigger_event, + "jitter": jitter, + "jitterOverlap": is_jitter_overlap, + "jitterMargin": jitter_margin, + "breaks": axisbreaks_opts, + "breakArea": axisbreak_area_opts, + "breakLabelLayout": axisbreak_label_layout_opts, "splitLine": splitline_opts, "splitArea": splitarea_opts, "minorTick": minor_tick_opts, "minorSplitLine": minor_split_line_opts, } + if animation_opts: + self.opts.update(**animation_opts.opts) + + +class GridOuterOpts(BasicOpts): + def __init__( + self, + pos_left: Union[Numeric, str, None] = None, + pos_top: Union[Numeric, str, None] = None, + pos_right: Union[Numeric, str, None] = None, + pos_bottom: Union[Numeric, str, None] = None, + width: Union[Numeric, str, None] = None, + height: Union[Numeric, str, None] = None, + ): + self.opts: dict = { + "left": pos_left, + "top": pos_top, + "right": pos_right, + "bottom": pos_bottom, + "width": width, + "height": height, + } + class GridOpts(BasicOpts): def __init__( @@ -697,10 +1126,24 @@ def __init__( width: Union[Numeric, str, None] = None, height: Union[Numeric, str, None] = None, is_contain_label: bool = False, + outer_bounds_mode: Optional[str] = None, + outer_bounds_opts: Union[GridOuterOpts, dict, None] = None, + outer_bounds_contain: Optional[str] = None, background_color: str = "transparent", border_color: str = "#ccc", border_width: Numeric = 1, + shadow_blur: Optional[Numeric] = None, + shadow_color: Optional[str] = None, + shadow_offset_x: Numeric = 0, + shadow_offset_y: Numeric = 0, tooltip_opts: Union[TooltipOpts, dict, None] = None, + coordinate_system: Optional[str] = None, + coordinate_system_usage: Optional[str] = None, + coord: Optional[Union[Sequence, Numeric, str]] = None, + calendar_index: Optional[Numeric] = None, + calendar_id: Optional[Numeric] = None, + matrix_index: Optional[Numeric] = None, + matrix_id: Optional[Numeric] = None, ): self.opts: dict = { "show": is_show, @@ -713,32 +1156,84 @@ def __init__( "width": width, "height": height, "containLabel": is_contain_label, + "outerBoundsMode": outer_bounds_mode, + "outerBounds": outer_bounds_opts, + "outerBoundsContain": outer_bounds_contain, "backgroundColor": background_color, "borderColor": border_color, "borderWidth": border_width, + "shadowBlur": shadow_blur, + "shadowColor": shadow_color, + "shadowOffsetX": shadow_offset_x, + "shadowOffsetY": shadow_offset_y, "tooltip": tooltip_opts, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, } class Grid3DOpts(BasicOpts): def __init__( self, + is_show: Optional[bool] = None, width: Numeric = 200, height: Numeric = 100, depth: Numeric = 80, is_rotate: bool = False, rotate_speed: Numeric = 10, rotate_sensitivity: Numeric = 1, + axisline_opts: Union[AxisLineOpts, dict, None] = None, + axistick_opts: Union[AxisTickOpts, dict, None] = None, + axislabel_opts: Union[LabelOpts, dict, None] = None, + axispointer_opts: Union[AxisPointerOpts, dict, None] = None, + splitarea_opts: Union[SplitAreaOpts, dict, None] = None, + splitline_opts: Union[SplitLineOpts, dict] = SplitLineOpts(is_show=True), + environment: JSFunc = "auto", + view_control_alpha: Numeric = 20, + view_control_beta: Numeric = 40, + view_control_min_alpha: Numeric = -90, + view_control_max_alpha: Numeric = 90, + view_control_min_beta: Optional[int] = None, + view_control_max_beta: Optional[int] = None, + z_level: Numeric = -10, + pos_left: Union[str, Numeric] = "auto", + pos_top: Union[str, Numeric] = "auto", + pos_right: Union[str, Numeric] = "auto", + pos_bottom: Union[str, Numeric] = "auto", ): self.opts: dict = { + "show": is_show, "boxWidth": width, "boxHeight": height, "boxDepth": depth, + "axisLine": axisline_opts, + "axisTick": axistick_opts, + "axisLabel": axislabel_opts, + "axisPointer": axispointer_opts, + "splitLine": splitline_opts, + "splitArea": splitarea_opts, + "environment": environment, "viewControl": { "autoRotate": is_rotate, "autoRotateSpeed": rotate_speed, "rotateSensitivity": rotate_sensitivity, + "alpha": view_control_alpha, + "beta": view_control_beta, + "minAlpha": view_control_min_alpha, + "maxAlpha": view_control_max_alpha, + "minBeta": view_control_min_beta, + "maxBeta": view_control_max_beta, }, + "zlevel": z_level, + "left": pos_left, + "top": pos_top, + "right": pos_right, + "bottom": pos_bottom, } @@ -748,24 +1243,41 @@ def __init__( data: Optional[Sequence] = None, type_: Optional[str] = None, name: Optional[str] = None, + is_show: bool = True, + is_scale: bool = False, + grid_3d_index: Numeric = 0, name_gap: Numeric = 20, min_: Union[str, Numeric, None] = None, max_: Union[str, Numeric, None] = None, - splitnum: Optional[Numeric] = None, - interval: Optional[Numeric] = None, - margin: Numeric = 8, + split_number: Optional[Numeric] = None, + log_base: Numeric = 10, + axisline_opts: Union[AxisLineOpts, dict, None] = None, + axistick_opts: Union[AxisTickOpts, dict, None] = None, + axislabel_opts: Union[LabelOpts, dict, None] = None, + axispointer_opts: Union[AxisPointerOpts, dict, None] = None, + splitarea_opts: Union[SplitAreaOpts, dict, None] = None, + splitline_opts: Union[SplitLineOpts, dict] = SplitLineOpts(is_show=True), textstyle_opts: Union[TextStyleOpts, dict, None] = None, ): self.opts: dict = { "data": data, "name": name, + "show": is_show, + "scale": is_scale, + "grid3DIndex": grid_3d_index, "nameGap": name_gap, "nameTextStyle": textstyle_opts, - "splitNum": splitnum, + "splitNumber": split_number, + "logBase": log_base, "type": type_, "min": min_, "max": max_, - "axisLabel": {"margin": margin, "interval": interval}, + "axisLine": axisline_opts, + "axisTick": axistick_opts, + "axisLabel": axislabel_opts, + "axisPointer": axispointer_opts, + "splitLine": splitline_opts, + "splitArea": splitarea_opts, } @@ -776,14 +1288,46 @@ def __init__( pos_right: str = "13%", pos_bottom: str = "10%", pos_top: str = "20%", + z_level: Optional[Numeric] = None, + z: Optional[Numeric] = None, + width: Optional[str] = None, + height: Optional[str] = None, + coordinate_system: Optional[str] = None, + coordinate_system_usage: Optional[str] = None, + coord: Optional[Union[Sequence, Numeric, str]] = None, + calendar_index: Optional[Numeric] = None, + calendar_id: Optional[Numeric] = None, + matrix_index: Optional[Numeric] = None, + matrix_id: Optional[Numeric] = None, layout: Optional[str] = None, + is_axis_expandable: bool = False, + axis_expand_center: Optional[Numeric] = None, + axis_expand_count: Numeric = 0, + axis_expand_width: Numeric = 50, + axis_expand_trigger_on: str = "click", ): self.opts: dict = { "left": pos_left, "right": pos_right, "bottom": pos_bottom, "top": pos_top, + "zlevel": z_level, + "z": z, + "width": width, + "height": height, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, "layout": layout, + "axisExpandable": is_axis_expandable, + "axisExpandCenter": axis_expand_center, + "axisExpandCount": axis_expand_count, + "axisExpandWidth": axis_expand_width, + "axisExpandTriggerOn": axis_expand_trigger_on, } @@ -791,21 +1335,47 @@ class ParallelAxisOpts(BasicOpts): def __init__( self, dim: Numeric, - name: str, + parallel_index: Numeric = 0, + is_realtime: bool = True, + name: Optional[str] = None, data: Sequence = None, type_: Optional[str] = None, + name_location: str = "end", + name_gap: Numeric = 15, + name_rotate: Optional[int] = None, + is_inverse: bool = False, min_: Union[str, Numeric, None] = None, max_: Union[str, Numeric, None] = None, is_scale: bool = False, + log_base: Numeric = 10, + is_silent: bool = False, + is_trigger_event: bool = False, + axisline_opts: Union[AxisLineOpts, dict, None] = None, + axistick_opts: Union[AxisTickOpts, dict, None] = None, + axislabel_opts: Union[LabelOpts, dict, None] = None, + minor_tick_opts: Union[MinorTickOpts, dict, None] = None, ): self.opts: dict = { "dim": dim, + "parallelIndex": parallel_index, + "realtime": is_realtime, "name": name, "data": data, "type": type_, + "name_location": name_location, + "name_gap": name_gap, + "name_rotate": name_rotate, + "inverse": is_inverse, "min": min_, "max": max_, "scale": is_scale, + "logBase": log_base, + "silent": is_silent, + "triggerEvent": is_trigger_event, + "axisLine": axisline_opts, + "axisTick": axistick_opts, + "axisLabel": axislabel_opts, + "minorTick": minor_tick_opts, } @@ -917,6 +1487,8 @@ def __init__( class CalendarOpts(BasicOpts): def __init__( self, + z_level: Numeric = 0, + z: Numeric = 2, pos_left: Optional[str] = None, pos_top: Optional[str] = None, pos_right: Optional[str] = None, @@ -931,8 +1503,11 @@ def __init__( daylabel_opts: Union[CalendarDayLabelOpts, dict, None] = None, monthlabel_opts: Union[CalendarMonthLabelOpts, dict, None] = None, yearlabel_opts: Union[CalendarYearLabelOpts, dict, None] = None, + is_silent: bool = False, ): self.opts: dict = { + "zlevel": z_level, + "z": z, "left": pos_left, "top": pos_top, "right": pos_right, @@ -947,6 +1522,7 @@ def __init__( "dayLabel": daylabel_opts, "monthLabel": monthlabel_opts, "yearLabel": yearlabel_opts, + "silent": is_silent, } @@ -964,6 +1540,15 @@ def __init__( height: Optional[str] = None, orient: Optional[str] = None, type_: Optional[str] = None, + axisline_opts: Union[AxisLineOpts, dict, None] = None, + axistick_opts: Union[AxisTickOpts, dict, None] = None, + axislabel_opts: Union[LabelOpts, dict, None] = None, + axispointer_opts: Union[AxisPointerOpts, dict, None] = None, + splitarea_opts: Union[SplitAreaOpts, dict, None] = None, + splitline_opts: Union[SplitLineOpts, dict, None] = None, + minor_tick_opts: Union[MinorTickOpts, dict, None] = None, + minor_split_line_opts: Union[MinorSplitLineOpts, dict, None] = None, + tooltip_opts: Union[TooltipOpts, dict, None] = None, ): self.opts: dict = { "name": name, @@ -977,6 +1562,15 @@ def __init__( "height": height, "orient": orient, "type": type_, + "axisLine": axisline_opts, + "axisTick": axistick_opts, + "minorTick": minor_tick_opts, + "axisLabel": axislabel_opts, + "splitLine": splitline_opts, + "minorSplitLine": minor_split_line_opts, + "splitArea": splitarea_opts, + "axisPointer": axispointer_opts, + "tooltip": tooltip_opts, } @@ -1007,16 +1601,25 @@ def __init__( type_: Optional[str] = None, name: Optional[str] = None, name_location: Optional[str] = None, + name_gap: Numeric = 15, + name_rotate: Optional[Numeric] = None, + is_inverse: bool = False, min_: Union[str, Numeric, None] = None, max_: Union[str, Numeric, None] = None, is_scale: bool = False, + split_number: Numeric = 5, interval: Optional[Numeric] = None, + min_interval: Numeric = 0, + max_interval: Optional[Numeric] = None, splitline_opts: Union[SplitLineOpts, dict, None] = None, splitarea_opts: Union[SplitAreaOpts, dict, None] = None, axistick_opts: Union[AxisTickOpts, dict, None] = None, axisline_opts: Union[AxisLineOpts, dict, None] = None, axislabel_opts: Union[LabelOpts, dict, None] = None, + minor_tick_opts: Union[MinorTickOpts, dict, None] = None, + minor_split_line_opts: Union[MinorSplitLineOpts, dict, None] = None, z: Optional[int] = None, + z_level: Optional[int] = None, ): _data = [] if data: @@ -1032,16 +1635,25 @@ def __init__( "boundaryGap": boundary_gap, "name": name, "nameLocation": name_location, + "nameGap": name_gap, + "nameRotate": name_rotate, + "inverse": is_inverse, "min": min_, "max": max_, "scale": is_scale, + "splitNumber": split_number, "interval": interval, + "minInterval": min_interval, + "maxInterval": max_interval, "splitLine": splitline_opts, "splitArea": splitarea_opts, "axisTick": axistick_opts, "axisLine": axisline_opts, "axisLabel": axislabel_opts, + "minorTick": minor_tick_opts, + "minorSplitLine": minor_split_line_opts, "z": z, + "zlevel": z_level, } @@ -1050,7 +1662,7 @@ def __init__( self, polar_index: Optional[int] = None, data: Optional[Sequence[Union[AngleAxisItem, Numeric, dict, str]]] = None, - start_angle: Optional[Numeric] = None, + start_angle: Optional[Numeric] = 90, is_clockwise: bool = False, boundary_gap: Union[bool, Sequence, None] = None, type_: Optional[str] = None, @@ -1063,7 +1675,10 @@ def __init__( axisline_opts: Union[AxisLineOpts, dict, None] = None, axistick_opts: Union[AxisTickOpts, dict, None] = None, axislabel_opts: Union[LabelOpts, dict, None] = None, + minor_tick_opts: Union[MinorTickOpts, dict, None] = None, + minor_split_line_opts: Union[MinorSplitLineOpts, dict, None] = None, z: Optional[int] = None, + z_level: Optional[int] = None, ): _data = [] if data: @@ -1088,7 +1703,10 @@ def __init__( "axisLine": axisline_opts, "axisTick": axistick_opts, "axisLabel": axislabel_opts, + "minorTick": minor_tick_opts, + "minorSplitLine": minor_split_line_opts, "z": z, + "zlevel": z_level, } @@ -1100,3 +1718,381 @@ def __init__( tooltip_opts: TooltipOpts = None, ): self.opts: dict = {"center": center, "radius": radius, "tooltip": tooltip_opts} + + +class DatasetTransformOpts(BasicOpts): + def __init__( + self, + type_: str = "filter", + config: Optional[dict] = None, + is_print: bool = False, + ): + self.opts: dict = {"type": type_, "config": config, "print": is_print} + + +class EmphasisOpts(BasicOpts): + def __init__( + self, + is_disabled: bool = False, + is_scale: bool = True, + focus: str = "none", + blur_scope: str = "coordinateSystem", + label_opts: Union[LabelOpts, dict, None] = None, + is_show_label_line: bool = False, + label_linestyle_opts: Union[LineStyleOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + linestyle_opts: Union[LineStyleOpts, dict, None] = None, + areastyle_opts: Union[AreaStyleOpts, dict, None] = None, + end_label_opts: Union[LabelOpts, dict, None] = None, + ): + self.opts: dict = { + "disabled": is_disabled, + "scale": is_scale, + "focus": focus, + "blurScope": blur_scope, + "label": label_opts, + "labelLine": { + "show": is_show_label_line, + "lineStyle": label_linestyle_opts + }, + "itemStyle": itemstyle_opts, + "lineStyle": linestyle_opts, + "areaStyle": areastyle_opts, + "endLabel": end_label_opts, + } + + +class Emphasis3DOpts(BasicOpts): + def __init__( + self, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + label_opts: Union[LabelOpts, dict, None] = None, + ): + self.opts: dict = { + "itemStyle": itemstyle_opts, + "label": label_opts, + } + + +class BlurOpts(BasicOpts): + def __init__( + self, + label_opts: Union[LabelOpts, dict, None] = None, + linestyle_opts: Union[LineStyleOpts, dict, None] = None, + is_show_label_line: bool = False, + label_linestyle_opts: Union[LineStyleOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + ): + self.opts: dict = { + "label": label_opts, + "lineStyle": linestyle_opts, + "labelLine": { + "show": is_show_label_line, + "lineStyle": label_linestyle_opts + }, + "itemStyle": itemstyle_opts, + } + + +class SelectOpts(BasicOpts): + def __init__( + self, + is_disabled: Optional[bool] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + linestyle_opts: Union[LineStyleOpts, dict, None] = None, + label_opts: Union[LabelOpts, dict, None] = None, + ): + self.opts: dict = { + "disabled": is_disabled, + "itemStyle": itemstyle_opts, + "lineStyle": linestyle_opts, + "label": label_opts, + } + + +class TreeLeavesOpts(BasicOpts): + def __init__( + self, + label_opts: Union[LabelOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + emphasis_opts: Union[EmphasisOpts, dict, None] = None, + blur_opts: Union[BlurOpts, dict, None] = None, + select_opts: Union[SelectOpts, dict, None] = None, + ): + self.opts: dict = { + "label": label_opts, + "itemStyle": itemstyle_opts, + "emphasis": emphasis_opts, + "blur": blur_opts, + "select": select_opts, + } + + +class MatrixDividerLineStyleOpts(BasicOpts): + def __init__( + self, + color: Optional[str] = "#aaa", + width: Optional[Numeric] = 1, + type_: Optional[str] = "solid", + dash_offset: Optional[Numeric] = 0, + cap: Optional[str] = "butt", + join: Optional[str] = "bevel", + miter_limit: Optional[Numeric] = 10, + shadow_blur: Optional[Numeric] = None, + shadow_color: Optional[str] = None, + shadow_offset_x: Optional[Numeric] = None, + shadow_offset_y: Optional[Numeric] = None, + opacity: Optional[Numeric] = 1, + ): + self.opts: dict = { + "color": color, + "width": width, + "type": type_, + "dashOffset": dash_offset, + "cap": cap, + "join": join, + "miterLimit": miter_limit, + "shadowBlur": shadow_blur, + "shadowColor": shadow_color, + "shadowOffsetX": shadow_offset_x, + "shadowOffsetY": shadow_offset_y, + "opacity": opacity, + } + + +class MatrixAxisDataOpts(BasicOpts): + def __init__( + self, + value: Union[Numeric, str] = None, + children: Union[dict, JSFunc, None] = None, + size: Optional[Numeric] = None, + ): + self.opts: dict = { + "value": value, + "children": children, + "size": size, + } + + +class MatrixAxisOpts(BasicOpts): + def __init__( + self, + is_show: bool = True, + data: Union[Sequence, dict, JSFunc, None] = None, + label_opts: Union[LabelOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + is_silent: bool = False, + cursor: Optional[str] = None, + z2: Optional[Numeric] = None, + level_size: Union[Numeric, str, None] = None, + levels: Optional[Sequence] = None, + divider_line_style_opts: Union[ + MatrixDividerLineStyleOpts, dict, None, + ] = None, + ): + self.opts: dict = { + "show": is_show, + "data": data, + "label": label_opts, + "itemStyle": itemstyle_opts, + "silent": is_silent, + "cursor": cursor, + "z2": z2, + "levelSize": level_size, + "levels": levels, + "dividerLineStyle": divider_line_style_opts, + } + + +class MatrixBodyDataOpts(BasicOpts): + def __init__( + self, + coord: Optional[Sequence] = None, + is_coord_clamp: Optional[bool] = None, + is_merge_cells: Optional[bool] = None, + value: Union[Numeric, str, None] = None, + label_opts: Union[LabelOpts, dict, None] = None, + ): + self.opts: dict = { + "coord": coord, + "coordClamp": is_coord_clamp, + "mergeCells": is_merge_cells, + "value": value, + "label": label_opts, + } + + +class MatrixBodyOrCornerOpts(BasicOpts): + def __init__( + self, + data: Union[Sequence[MatrixBodyDataOpts], dict, None] = None, + label_opts: Union[LabelOpts, dict, None] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + is_silent: bool = False, + cursor: Optional[str] = None, + z2: Optional[Numeric] = None, + ): + self.opts: dict = { + "data": data, + "label": label_opts, + "itemStyle": itemstyle_opts, + "silent": is_silent, + "cursor": cursor, + "z2": z2, + } + + +class MatrixBackgroundStyleOpts(BasicOpts): + def __init__( + self, + color: Optional[str] = None, + border_color: str = "#ccc", + border_width: Numeric = 1, + border_type: str = "solid", + border_radius: Union[Numeric, Sequence] = 0, + border_cap: str = "butt", + border_join: str = "bevel", + border_miter_limit: Optional[Numeric] = 10, + shadow_blur: Optional[Numeric] = None, + shadow_color: Optional[str] = None, + shadow_offset_x: Numeric = 0, + shadow_offset_y: Numeric = 0, + opacity: Optional[Numeric] = 1, + ): + self.opts: dict = { + "color": color, + "borderColor": border_color, + "borderWidth": border_width, + "borderType": border_type, + "borderRadius": border_radius, + "borderCap": border_cap, + "borderJoin": border_join, + "borderMiterLimit": border_miter_limit, + "shadowBlur": shadow_blur, + "shadowColor": shadow_color, + "shadowOffsetX": shadow_offset_x, + "shadowOffsetY": shadow_offset_y, + "opacity": opacity, + } + + +class MatrixOpts(BasicOpts): + def __init__( + self, + z_level: Numeric = 0, + z: Numeric = 2, + pos_left: Union[Numeric, str, None] = None, + pos_top: Union[Numeric, str, None] = None, + pos_right: Union[Numeric, str, None] = None, + pos_bottom: Union[Numeric, str, None] = None, + width: Union[Numeric, str, None] = None, + height: Union[Numeric, str, None] = None, + x_data: Union[MatrixAxisOpts, dict, None] = None, + y_data: Union[MatrixAxisOpts, dict, None] = None, + body_opts: Union[MatrixBodyOrCornerOpts, dict, None] = None, + corner_opts: Union[MatrixBodyOrCornerOpts, dict, None] = None, + background_style: Union[MatrixBackgroundStyleOpts, dict, None] = None, + border_z2: Optional[Numeric] = None, + tooltip_opts: TooltipOpts = None, + ): + self.opts: dict = { + "zlevel": z_level, + "z": z, + "left": pos_left, + "top": pos_top, + "right": pos_right, + "bottom": pos_bottom, + "width": width, + "height": height, + "x": x_data, + "y": y_data, + "body": body_opts, + "corner": corner_opts, + "backgroundStyle": background_style, + "borderZ2": border_z2, + "tooltip": tooltip_opts, + } + + +class ThumbnailWindowStyleOpts(BasicOpts): + def __init__( + self, + color: Optional[str] = "#9ea0a5", + border_color: str = "#b7b9be", + border_width: Numeric = 1, + border_type: str = "solid", + border_dash_offset: Numeric = 0, + border_cap: str = "butt", + border_join: str = "bevel", + border_miter_limit: Optional[Numeric] = 10, + shadow_blur: Optional[Numeric] = None, + shadow_color: Optional[str] = None, + shadow_offset_x: Numeric = 0, + shadow_offset_y: Numeric = 0, + opacity: Optional[Numeric] = 0.3, + ): + self.opts: dict = { + "color": color, + "borderColor": border_color, + "borderWidth": border_width, + "borderType": border_type, + "borderDashOffset": border_dash_offset, + "borderCap": border_cap, + "borderJoin": border_join, + "borderMiterLimit": border_miter_limit, + "shadowBlur": shadow_blur, + "shadowColor": shadow_color, + "shadowOffsetX": shadow_offset_x, + "shadowOffsetY": shadow_offset_y, + "opacity": opacity, + } + + +class ThumbnailOpts(BasicOpts): + def __init__( + self, + is_show: bool = True, + z_level: Numeric = 0, + z: Numeric = 2, + pos_left: Union[Numeric, str, None] = None, + pos_top: Union[Numeric, str, None] = None, + pos_right: Union[Numeric, str, None] = None, + pos_bottom: Union[Numeric, str, None] = None, + width: Union[Numeric, str, None] = None, + height: Union[Numeric, str, None] = None, + coordinate_system: Optional[str] = None, + coordinate_system_usage: Optional[str] = None, + coord: Optional[Union[Sequence, Numeric, str]] = None, + calendar_index: Optional[Numeric] = None, + calendar_id: Optional[Numeric] = None, + matrix_index: Optional[Numeric] = None, + matrix_id: Optional[Numeric] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + window_style_opts: Union[ + ThumbnailWindowStyleOpts, dict, None, + ] = None, + series_index: Optional[Numeric] = None, + series_id: Union[Numeric, str, None] = None, + ): + self.opts: dict = { + "show": is_show, + "zlevel": z_level, + "z": z, + "left": pos_left, + "top": pos_top, + "right": pos_right, + "bottom": pos_bottom, + "width": width, + "height": height, + "coordinateSystem": coordinate_system, + "coordinateSystemUsage": coordinate_system_usage, + "coord": coord, + "calendarIndex": calendar_index, + "calendarId": calendar_id, + "matrixIndex": matrix_index, + "matrixId": matrix_id, + "itemStyle": itemstyle_opts, + "windowStyle": window_style_opts, + "seriesIndex": series_index, + "seriesId": series_id, + } diff --git a/pyecharts/options/series_options.py b/pyecharts/options/series_options.py index b6c5b6e5c..7e59a436f 100644 --- a/pyecharts/options/series_options.py +++ b/pyecharts/options/series_options.py @@ -16,6 +16,30 @@ def get(self, key: str) -> Any: return self.opts.get(key) +class AnimationOpts(BasicOpts): + def __init__( + self, + animation: bool = True, + animation_threshold: Numeric = 2000, + animation_duration: Union[Numeric, JSFunc] = 1000, + animation_easing: Union[str] = "cubicOut", + animation_delay: Union[Numeric, JSFunc] = 0, + animation_duration_update: Union[Numeric, JSFunc] = 300, + animation_easing_update: Union[str] = "cubicOut", + animation_delay_update: Union[Numeric, JSFunc] = 0, + ): + self.opts: dict = { + "animation": animation, + "animationThreshold": animation_threshold, + "animationDuration": animation_duration, + "animationEasing": animation_easing, + "animationDelay": animation_delay, + "animationDurationUpdate": animation_duration_update, + "animationEasingUpdate": animation_easing_update, + "animationDelayUpdate": animation_delay_update, + } + + class ItemStyleOpts(BasicOpts): def __init__( self, @@ -25,6 +49,7 @@ def __init__( border_color0: Optional[str] = None, border_width: Optional[Numeric] = None, border_type: Optional[str] = None, + border_radius: Optional[Numeric] = None, opacity: Optional[Numeric] = None, area_color: Optional[str] = None, ): @@ -35,6 +60,7 @@ def __init__( "borderColor0": border_color0, "borderWidth": border_width, "borderType": border_type, + "borderRadius": border_radius, "opacity": opacity, "areaColor": area_color, } @@ -61,6 +87,7 @@ def __init__( width: Optional[str] = None, height: Optional[str] = None, rich: Optional[dict] = None, + is_rich_inherit_plain_label: bool = True, ): self.opts: dict = { "color": color, @@ -81,6 +108,7 @@ def __init__( "width": width, "height": height, "rich": rich, + "richInheritPlainLabel": is_rich_inherit_plain_label, } @@ -88,15 +116,19 @@ class LabelOpts(BasicOpts): def __init__( self, is_show: bool = True, - position: Union[str, Sequence] = "top", + position: Optional[Union[str, Sequence]] = None, color: Optional[str] = None, + opacity: Optional[Numeric] = None, distance: Union[Numeric, Sequence, None] = None, font_size: Optional[Numeric] = None, font_style: Optional[str] = None, font_weight: Optional[str] = None, font_family: Optional[str] = None, rotate: Optional[Numeric] = None, + offset: Optional[Sequence[Numeric]] = None, margin: Optional[Numeric] = 8, + text_margin: Union[Numeric, Sequence, None] = None, + min_margin: Optional[Numeric] = None, interval: Union[Numeric, str, None] = None, horizontal_align: Optional[str] = None, vertical_align: Optional[str] = None, @@ -105,15 +137,32 @@ def __init__( border_color: Optional[str] = None, border_width: Optional[Numeric] = None, border_radius: Optional[Numeric] = None, + padding: Union[Numeric, Sequence[Numeric], None] = None, + text_width: Optional[Numeric] = None, + text_height: Optional[Numeric] = None, + text_border_color: Optional[str] = None, + text_border_width: Optional[Numeric] = None, + text_shadow_color: Optional[str] = None, + text_shadow_blur: Optional[Numeric] = None, + text_shadow_offset_x: Optional[Numeric] = None, + text_shadow_offset_y: Optional[Numeric] = None, + overflow: Optional[str] = None, rich: Optional[dict] = None, + is_rich_inherit_plain_label: bool = True, + is_value_animation: bool = False, + text_style_opts: Optional[TextStyleOpts] = None, ): self.opts: dict = { "show": is_show, "position": position, "color": color, + "opacity": opacity, "distance": distance, "rotate": rotate, + "offset": offset, "margin": margin, + "textMargin": text_margin, + "minMargin": min_margin, "interval": interval, "fontSize": font_size, "fontStyle": font_style, @@ -126,18 +175,31 @@ def __init__( "borderColor": border_color, "borderWidth": border_width, "borderRadius": border_radius, + "padding": padding, + "width": text_width, + "height": text_height, + "textBorderColor": text_border_color, + "textBorderWidth": text_border_width, + "textShadowColor": text_shadow_color, + "textShadowBlur": text_shadow_blur, + "textShadowOffsetX": text_shadow_offset_x, + "textShadowOffsetY": text_shadow_offset_y, + "overflow": overflow, "rich": rich, + "richInheritPlainLabel": is_rich_inherit_plain_label, + "valueAnimation": is_value_animation, + "textStyle": text_style_opts, } class LineStyleOpts(BasicOpts): def __init__( self, - is_show: bool = True, - width: Numeric = 1, - opacity: Numeric = 1, - curve: Numeric = 0, - type_: str = "solid", + is_show: bool = False, + width: Optional[Numeric] = None, + opacity: Optional[Numeric] = None, + curve: Optional[Numeric] = None, + type_: Optional[str] = None, color: Union[str, Sequence, None] = None, ): self.opts: dict = { @@ -170,7 +232,11 @@ def __init__( value: Optional[Numeric] = None, symbol: Optional[str] = None, symbol_size: Union[Numeric, Sequence, None] = None, + symbol_rotate: Optional[Numeric] = None, + symbol_keep_aspect: bool = None, + symbol_offset: Optional[Sequence] = None, itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + label_opts: Optional[LabelOpts] = None, ): self.opts: dict = { "name": name, @@ -183,7 +249,11 @@ def __init__( "value": value, "symbol": symbol, "symbolSize": symbol_size, + "symbolRotate": symbol_rotate, + "symbolKeepAspect": symbol_keep_aspect, + "symbolOffset": symbol_offset, "itemStyle": itemstyle_opts, + "label": label_opts, } @@ -193,15 +263,29 @@ def __init__( data: Sequence[Union[MarkPointItem, dict]] = None, symbol: Optional[str] = None, symbol_size: Union[None, Numeric] = None, - label_opts: LabelOpts = LabelOpts(position="inside", color="#fff"), + symbol_rotate: Optional[Numeric] = None, + symbol_keep_aspect: bool = None, + symbol_offset: Optional[Sequence] = None, + silent: bool = None, + label_opts: Optional[LabelOpts] = None, + itemstyle_opts: Union[ItemStyleOpts, dict, None] = None, + animation_opts: Union[AnimationOpts, dict, None] = None, ): self.opts: dict = { "symbol": symbol, "symbolSize": symbol_size, + "symbolRotate": symbol_rotate, + "symbolKeepAspect": symbol_keep_aspect, + "symbolOffset": symbol_offset, + "silent": silent, "label": label_opts, + "itemStyle": itemstyle_opts, "data": data, } + if animation_opts: + self.opts.update(**animation_opts.opts) + class MarkLineItem(BasicOpts): def __init__( @@ -215,6 +299,7 @@ def __init__( value_index: Optional[Numeric] = None, value_dim: Optional[str] = None, coord: Optional[Sequence] = None, + linestyle_opts: Union[LineStyleOpts, dict, None] = None, symbol: Optional[str] = None, symbol_size: Optional[Numeric] = None, ): @@ -227,6 +312,7 @@ def __init__( "x": xcoord, "yAxis": y, "y": ycoord, + "lineStyle": linestyle_opts, "coord": coord, "symbol": symbol, "symbolSize": symbol_size, @@ -243,6 +329,7 @@ def __init__( precision: int = 2, label_opts: LabelOpts = LabelOpts(), linestyle_opts: Union[LineStyleOpts, dict, None] = None, + animation_opts: Union[AnimationOpts, dict, None] = None, ): self.opts: dict = { "silent": is_silent, @@ -254,6 +341,9 @@ def __init__( "data": data, } + if animation_opts: + self.opts.update(**animation_opts.opts) + class MarkAreaItem(BasicOpts): def __init__( @@ -295,6 +385,7 @@ def __init__( label_opts: LabelOpts = LabelOpts(), data: Sequence[Union[MarkAreaItem, Sequence, dict]] = None, itemstyle_opts: ItemStyleOpts = None, + animation_opts: Union[AnimationOpts, dict, None] = None, ): self.opts: dict = { "silent": is_silent, @@ -303,6 +394,9 @@ def __init__( "itemStyle": itemstyle_opts, } + if animation_opts: + self.opts.update(**animation_opts.opts) + class EffectOpts(BasicOpts): def __init__( @@ -351,8 +445,23 @@ def __init__( class AreaStyleOpts(BasicOpts): - def __init__(self, opacity: Optional[Numeric] = 0, color: Optional[str] = None): - self.opts: dict = {"opacity": opacity, "color": color} + def __init__( + self, + opacity: Optional[Numeric] = 0, + color: Optional[JSFunc] = None, + shadow_blur: Optional[Numeric] = None, + shadow_color: Optional[str] = None, + shadow_offset_x: Optional[Numeric] = None, + shadow_offset_y: Optional[Numeric] = None, + ): + self.opts: dict = { + "opacity": opacity, + "color": color, + "shadowBlur": shadow_blur, + "shadowColor": shadow_color, + "shadowOffsetX": shadow_offset_x, + "shadowOffsetY": shadow_offset_y, + } class SplitAreaOpts(BasicOpts): @@ -416,3 +525,37 @@ def __init__( "opacity": opacity, "lineStyle": linestyle_opts, } + + +class GraphGLForceAtlas2Opts(BasicOpts): + def __init__( + self, + is_gpu: bool = True, + steps: Numeric = 1, + stop_threshold: Numeric = 1, + is_barnes_hut_optimize: Optional[bool] = None, + is_repulsion_by_degree: bool = True, + is_lin_log_mode: bool = False, + gravity: Numeric = 1, + gravity_center: Optional[Sequence] = None, + scaling: Optional[Numeric] = None, + edge_weight_influence: Numeric = 1, + edge_weight: Union[Sequence, Numeric] = None, + node_weight: Union[Sequence, Numeric] = None, + is_prevent_overlap: bool = False, + ): + self.opts: dict = { + "GPU": is_gpu, + "steps": steps, + "stopThreshold": stop_threshold, + "barnesHutOptimize": is_barnes_hut_optimize, + "repulsionByDegree": is_repulsion_by_degree, + "linLogMode": is_lin_log_mode, + "gravity": gravity, + "gravityCenter": gravity_center, + "scaling": scaling, + "edgeWeightInfluence": edge_weight_influence, + "edgeWeight": edge_weight, + "nodeWeight": node_weight, + "preventOverlap": is_prevent_overlap, + } diff --git a/pyecharts/render/display.py b/pyecharts/render/display.py index f419adef8..78c93e2a0 100644 --- a/pyecharts/render/display.py +++ b/pyecharts/render/display.py @@ -1,4 +1,6 @@ from ..types import Optional, Sequence, Union +from urllib.parse import urlparse +import http.client class HTML: @@ -50,6 +52,7 @@ def __init__( self.lib = lib self.css = css self.data = data or "" + self.javascript_contents = dict() def _repr_javascript_(self): r = "" @@ -60,3 +63,24 @@ def _repr_javascript_(self): r += self.data r += _lib_t2 * len(self.lib) return r + + def load_javascript_contents(self): + for lib in self.lib: + parsed_url = urlparse(lib) + + host: str = str(parsed_url.hostname) + port: int = parsed_url.port + path: str = parsed_url.path + + resp: Optional[http.client.HTTPResponse] = None + try: + conn = http.client.HTTPSConnection(host, port) + conn.request("GET", path) + resp = conn.getresponse() + if resp.status != 200: + raise RuntimeError("Cannot load JavaScript lib: %s" % lib) + self.javascript_contents[lib] = resp.read().decode("utf-8") + finally: + if resp is not None: + resp.close() + return self diff --git a/pyecharts/render/engine.py b/pyecharts/render/engine.py index 8a267cd9f..715286376 100644 --- a/pyecharts/render/engine.py +++ b/pyecharts/render/engine.py @@ -1,17 +1,24 @@ import os -from collections import Iterable + +try: + from collections.abc import Iterable +except ImportError: + from collections import Iterable from jinja2 import Environment from ..commons import utils from ..datasets import EXTRA, FILENAMES -from ..globals import CurrentConfig, NotebookType +from ..globals import CurrentConfig, NotebookType, RenderSepType from ..types import Any, Optional from .display import HTML, Javascript def write_utf8_html_file(file_name: str, html_content: str): - with open(file_name, "w+", encoding="utf-8") as html_file: + with open(file=file_name, + mode="w+", + encoding="utf-8", + newline=RenderSepType.SepType) as html_file: html_file.write(html_content) @@ -24,20 +31,37 @@ def generate_js_link(chart: Any) -> Any: if not chart.js_host: chart.js_host = CurrentConfig.ONLINE_HOST links = [] + css_links = [] for dep in chart.js_dependencies.items: # TODO: if? if dep.startswith("https://api.map.baidu.com"): links.append(dep) + if dep.startswith("https://webapi.amap.com"): + links.append(dep) + if dep.startswith("https://maps.googleapis.com"): + links.append(dep) if dep in FILENAMES: f, ext = FILENAMES[dep] - links.append("{}{}.{}".format(chart.js_host, f, ext)) + _link = "{}{}.{}".format(chart.js_host, f, ext) + if ext == "css": + css_links.append(_link) + else: + links.append(_link) else: for url, files in EXTRA.items(): if dep in files: f, ext = files[dep] - links.append("{}{}.{}".format(url, f, ext)) + _link = "{}{}.{}".format(url, f, ext) + if ext == "css": + css_links.append(_link) + else: + links.append(_link) break chart.dependencies = links + if hasattr(chart, "css_libs"): + chart.css_libs = chart.css_libs + css_links + else: + chart.css_libs = css_links return chart def render_chart_to_file(self, template_name: str, chart: Any, path: str, **kwargs): diff --git a/pyecharts/render/snapshot.py b/pyecharts/render/snapshot.py index dbe49427a..62e40f3a4 100644 --- a/pyecharts/render/snapshot.py +++ b/pyecharts/render/snapshot.py @@ -91,7 +91,9 @@ def save_as(image_data: bytes, output_name: str, file_type: str): m.load() color = (255, 255, 255) b = Image.new("RGB", m.size, color) - b.paste(m, mask=m.split()[3]) + # BUG for Mac: + # b.paste(m, mask=m.split()[3]) + b.paste(m) b.save(output_name, file_type, quality=100) except ModuleNotFoundError: raise Exception(f"Please install PIL for {file_type} image type") diff --git a/pyecharts/render/templates/macro b/pyecharts/render/templates/macro index 691d1ed64..71c203b23 100644 --- a/pyecharts/render/templates/macro +++ b/pyecharts/render/templates/macro @@ -1,19 +1,86 @@ {%- macro render_chart_content(c) -%} -

+
+ {% if c._geo_json_name and c._geo_json %} + {% endif %} + {%- endmacro %} @@ -30,15 +102,57 @@ {% for c in charts %} {% if c._component_type not in ("table", "image") %} var chart_{{ c.chart_id }} = echarts.init( - document.getElementById('{{ c.chart_id }}'), '{{ c.theme }}', {renderer: '{{ c.renderer }}'}); + document.getElementById('{{ c.chart_id }}'), '{{ c.theme }}', {renderer: '{{ c.renderer }}', locale: '{{ c.locale }}'}); {% for js in c.js_functions.items %} {{ js }} {% endfor %} var option_{{ c.chart_id }} = {{ c.json_contents }}; chart_{{ c.chart_id }}.setOption(option_{{ c.chart_id }}); {% if c._is_geo_chart %} - var bmap = chart_{{ c.chart_id }}.getModel().getComponent('bmap').getBMap(); - bmap.addControl(new BMap.MapTypeControl()); + {% if c._coordinate_system == 'bmap' %} + var bmap = chart_{{ c.chart_id }}.getModel().getComponent('bmap').getBMap(); + {% if c.bmap_js_functions %} + {% for fn in c.bmap_js_functions.items %} + {{ fn }} + {% endfor %} + {% endif %} + {% elif c._coordinate_system == 'amap' %} + // Get AMap extension component + var amapComponent = chart_{{ c.chart_id }}.getModel().getComponent('amap'); + // Get the instance of AMap + var amap = amapComponent.getAMap(); + // Add some controls provided by AMap. + amap.addControl(new AMap.Scale()); + amap.addControl(new AMap.ToolBar()); + {% if c.amap_js_functions %} + {% for fn in c.amap_js_functions.items %} + {{ fn }} + {% endfor %} + {% endif %} + {% elif c._coordinate_system == 'lmap' %} + var lmapComponent = chart_{{ c.chart_id }}.getModel().getComponent('lmap'); + var lmap = lmapComponent.getLeaflet(); + L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { + attribution: '©
OpenStreetMap contributors' + }).addTo(lmap); + {% elif c._coordinate_system == 'gmap' %} + // Get the instance of Google Map + var gmap = chart_{{ c.chart_id }}.getModel().getComponent('gmap').getGoogleMap(); + // Add some markers to map + var marker = new google.maps.Marker({ position: gmap.getCenter() }); + marker.setMap(gmap); + // Add TrafficLayer to map + {% if c.gmap_js_functions %} + {% for fn in c.gmap_js_functions.items %} + {{ fn }} + {% endfor %} + {% endif %} + {% endif %} + {% endif %} + {% if c.js_events %} + {% for fn in c.js_events.items %} + {{ fn }} + {% endfor %} {% endif %} {% endif %} {% endfor %} @@ -47,14 +161,23 @@ {%- endmacro %} {%- macro render_chart_dependencies(c) -%} - {% for dep in c.dependencies %} - - {% endfor %} + {% if 'embed_js' in c.render_options and 'javascript' in c._render_cache and c.render_options.embed_js -%} + {% set _javascript = c._render_cache.javascript %} + {% for dep in c.dependencies %} + + {% endfor %} + {%- else -%} + {% for dep in c.dependencies %} + + {% endfor %} + {%- endif %} {%- endmacro %} {%- macro render_chart_css(c) -%} {% for dep in c.css_libs %} - + {% endfor %} {%- endmacro %} @@ -119,9 +242,11 @@ } .chart-container { + display: block; + } + + .chart-container:nth-child(n+2) { display: none; - padding: 6px 12px; - border-top: none; } {%- endmacro %} diff --git a/pyecharts/render/templates/nb_jupyter_globe.html b/pyecharts/render/templates/nb_jupyter_globe.html index e9b4d442a..88c3a0c2e 100644 --- a/pyecharts/render/templates/nb_jupyter_globe.html +++ b/pyecharts/render/templates/nb_jupyter_globe.html @@ -20,7 +20,7 @@ var mapOption_{{ c.chart_id }} = {{ c.json_contents }}; mapChart_{{ c.chart_id }}.setOption(mapOption_{{ c.chart_id }}); var chart_{{ c.chart_id }} = echarts.init( - document.getElementById('{{ c.chart_id }}'), '{{ c.theme }}', {renderer: '{{ c.renderer }}'}); + document.getElementById('{{ c.chart_id }}'), '{{ c.theme }}', {renderer: '{{ c.renderer }}', locale: '{{ c.locale }}'}); {% for js in c.js_functions.items %} {{ js }} {% endfor %} diff --git a/pyecharts/render/templates/nb_nteract.html b/pyecharts/render/templates/nb_nteract.html index c975bcf8b..c9739b387 100644 --- a/pyecharts/render/templates/nb_nteract.html +++ b/pyecharts/render/templates/nb_nteract.html @@ -3,7 +3,7 @@ - {{ macro.render_chart_dependencies(chart) }} + {{ macro.render_chart_dependencies(chart, _inner, _javascript) }} {% for c in chart %} diff --git a/pyecharts/render/templates/simple_chart.html b/pyecharts/render/templates/simple_chart.html index 4f4573959..268516a75 100644 --- a/pyecharts/render/templates/simple_chart.html +++ b/pyecharts/render/templates/simple_chart.html @@ -5,8 +5,9 @@ {{ chart.page_title }} {{ macro.render_chart_dependencies(chart) }} + {{ macro.render_chart_css(chart) }} - + {{ macro.render_chart_content(chart) }} diff --git a/pyecharts/render/templates/simple_globe.html b/pyecharts/render/templates/simple_globe.html index ad37793bc..b9e4bbe4f 100644 --- a/pyecharts/render/templates/simple_globe.html +++ b/pyecharts/render/templates/simple_globe.html @@ -19,7 +19,7 @@ mapChart_{{ chart.chart_id }}.setOption(mapOption_{{ chart.chart_id }}); var chart_{{ chart.chart_id }} = echarts.init( - document.getElementById('{{ chart.chart_id }}'), '{{ chart.theme }}', {renderer: '{{ chart.renderer }}'}); + document.getElementById('{{ chart.chart_id }}'), '{{ chart.theme }}', {renderer: '{{ chart.renderer }}', locale: '{{ chart.locale }}'}); var options_{{ chart.chart_id }} = { "globe": { "show": true, diff --git a/pyecharts/render/templates/simple_page.html b/pyecharts/render/templates/simple_page.html index 19dc639e6..84a3e03b1 100644 --- a/pyecharts/render/templates/simple_page.html +++ b/pyecharts/render/templates/simple_page.html @@ -7,8 +7,8 @@ {{ macro.render_chart_dependencies(chart) }} {{ macro.render_chart_css(chart) }} - - + + {% if chart.download_button %} {% endif %} @@ -19,7 +19,9 @@ {% else %} {{ macro.render_chart_content(c) }} {% endif %} - {% for _ in range(chart.page_interval) %}
{% endfor %} + {% for _ in range(chart.page_interval) %} + {% if chart.remove_br is false %}
{% endif %} + {% endfor %} {% endfor %}