diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8371e0a..17c8f20 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -119,14 +119,15 @@ jobs: - name: Install browser shell: bash -l {0} - run: npx playwright install chromium working-directory: ui-tests + run: | + jlpm install + npx playwright install chromium - name: Execute integration tests shell: bash -l {0} working-directory: ui-tests run: | - jlpm install npx playwright test - name: Upload Playwright Test report diff --git a/README.md b/README.md index 16dbdd9..fd24a59 100644 --- a/README.md +++ b/README.md @@ -255,3 +255,18 @@ chart.on('mouseover', {'seriesIndex': 1, 'name': 'xx'}, callback) # Using object chart.off('click') # Remove all handler on click event chart.off('mouseover', callback) # Remove selected handler. ``` + +### Chart actions + +Chart actions supported by ECharts can by triggered by the `EChartsWidget.dispatchAction` or `EChartsRawWidget.dispatchAction` method. This method takes the same payload as [in the Javascript version](https://echarts.apache.org/en/api.html#action): + +```python +chart = EChartsWidget(option=option) +chart.dispatchAction({ + 'type': 'highlight', + 'seriesIndex': 0, + 'dataIndex': 1 + }) +``` + +![ipechart](./docs/source/images/ipecharts_action.gif) diff --git a/docs/source/api/ipecharts.rst b/docs/source/api/ipecharts.rst index 898718f..c0fcec2 100644 --- a/docs/source/api/ipecharts.rst +++ b/docs/source/api/ipecharts.rst @@ -18,6 +18,7 @@ Submodules ipecharts.baseechartswidget ipecharts.basewidget ipecharts.echarts + ipecharts.tools Module contents --------------- diff --git a/docs/source/api/ipecharts.tools.rst b/docs/source/api/ipecharts.tools.rst new file mode 100644 index 0000000..0bcdfb0 --- /dev/null +++ b/docs/source/api/ipecharts.tools.rst @@ -0,0 +1,7 @@ +ipecharts.tools module +====================== + +.. automodule:: ipecharts.tools + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/images/ipecharts_action.gif b/docs/source/images/ipecharts_action.gif new file mode 100644 index 0000000..9503bc3 Binary files /dev/null and b/docs/source/images/ipecharts_action.gif differ diff --git a/docs/source/index.rst b/docs/source/index.rst index 79153d3..3273956 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -256,6 +256,21 @@ Event-handling functions can be added to ``EChartsWidget`` and ``EChartsRawWidge chart.off('click') # Remove all handler on click event chart.off('mouseover', callback) # Remove selected handler. +Chart actions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Chart actions supported by ECharts can by triggered by the ``EChartsWidget.dispatchAction`` or ``EChartsRawWidget.dispatchAction`` method. This method takes the same payload as [in the Javascript version](https://echarts.apache.org/en/api.html#action): + +.. code-block:: python + + chart = EChartsWidget(option=option) + chart.dispatchAction({ + 'type': 'highlight', + 'seriesIndex': 0, + 'dataIndex': 1 + }) + +.. figure:: images/ipecharts_action.gif API Reference ******************************** diff --git a/example/action.ipynb b/example/action.ipynb new file mode 100644 index 0000000..03a6efb --- /dev/null +++ b/example/action.ipynb @@ -0,0 +1,178 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 37, + "id": "6144d5b4-faf0-4401-8691-3a56dddb519d", + "metadata": {}, + "outputs": [], + "source": [ + "from ipecharts.echarts import EChartsWidget, EChartsRawWidget\n", + "import json\n", + "import numpy\n", + "from ipecharts.option import Option, XAxis, YAxis, Legend, Tooltip, Grid\n", + "from ipecharts.option.series import Pie\n", + "from ipywidgets.widgets import Button" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "65231639-b78b-41fd-8cac-89de1d3fa41f", + "metadata": {}, + "outputs": [], + "source": [ + "tooltip = Tooltip(trigger='item', formatter='{a}
{b} : {c} ({d}%)')" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "0b449694-d1ab-430d-9520-4f71c3233607", + "metadata": {}, + "outputs": [], + "source": [ + "legend = Legend(orient='vertical', left='left', data=['Direct Access','Email Marketing','Affiliate Ads','Video Ads','Search Engines'])" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "fd8570d4-e3e4-45d4-9508-77a1939b6d12", + "metadata": {}, + "outputs": [], + "source": [ + "pie = Pie(\n", + " name='Access Source',\n", + " radius='55%',\n", + " center=['50%', '60%'],\n", + " data=[\n", + " { 'value': 335, 'name': 'Direct Access' },\n", + " { 'value': 310, 'name': 'Email Marketing' },\n", + " { 'value': 234, 'name': 'Affiliate Ads' },\n", + " { 'value': 135, 'name': 'Video Ads' },\n", + " { 'value': 1548, 'name': 'Search Engines' }\n", + " ],\n", + " emphasis={\n", + " 'itemStyle': {\n", + " 'shadowBlur': 10,\n", + " 'shadowOffsetX': 0,\n", + " 'shadowColor': 'rgba(0, 0, 0, 0.5)'\n", + " }\n", + " }\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "6b73428e-1e73-4adf-a09a-7b1707cdba84", + "metadata": {}, + "outputs": [], + "source": [ + "chart = EChartsWidget(option=Option(series=[pie], tooltip=tooltip, legend=legend))" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "e9127c30-8f1d-4894-8ad8-6caa18c15a53", + "metadata": {}, + "outputs": [], + "source": [ + "button = Button(description=\"Dispatch Action\")\n", + "currentIndex = -1\n", + "dataLen = 5\n", + "def on_button_clicked(b):\n", + " global currentIndex\n", + " chart.dispatchAction({\n", + " 'type': 'downplay',\n", + " 'seriesIndex': 0,\n", + " 'dataIndex': currentIndex\n", + " })\n", + " currentIndex = (currentIndex + 1) % dataLen\n", + " chart.dispatchAction({\n", + " 'type': 'highlight',\n", + " 'seriesIndex': 0,\n", + " 'dataIndex': currentIndex\n", + " })\n", + " chart.dispatchAction({\n", + " 'type': 'showTip',\n", + " 'seriesIndex': 0,\n", + " 'dataIndex': currentIndex\n", + " })\n", + "\n", + "button.on_click(on_button_clicked)" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "2c04edee-f416-436b-808b-83d1915c8df7", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "ddbd04409e4147d6a55716e347512db2", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "EChartsWidget(option=Option(angleAxis=None, aria=None, axisPointer=None, brush=None, calendar=None, dataset=No…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "216a688b3116434ca3719692de853dc7", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Button(description='Dispatch Action', style=ButtonStyle())" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "display(chart, button)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "848cd0e5-82b6-4c34-8a89-a3a9eecb1633", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "jupyter_suggestion": {}, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.15" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ipecharts/baseechartswidget.py b/ipecharts/baseechartswidget.py index a9fd173..cab0b8a 100644 --- a/ipecharts/baseechartswidget.py +++ b/ipecharts/baseechartswidget.py @@ -109,6 +109,14 @@ def off(self, event_name: str, handler: T.Optional[T.Callable] = None): } ) + def dispatchAction(self, payload: T.Dict): + self.send( + { + "action": MESSAGE_ACTION.DISPATCH_ACTION, + "payload": payload, + } + ) + def _handle_frontend_msg( self, model: "BaseEchartsWidget", msg: T.Dict, buffers: T.List ) -> None: diff --git a/ipecharts/tools.py b/ipecharts/tools.py index 0434e2a..0bc0a94 100644 --- a/ipecharts/tools.py +++ b/ipecharts/tools.py @@ -2,4 +2,5 @@ class MESSAGE_ACTION(str, Enum): REGISTER_EVENT = 'register_event' - UNREGISTER_EVENT = 'unregister_event' \ No newline at end of file + UNREGISTER_EVENT = 'unregister_event' + DISPATCH_ACTION = 'dispatch_action' \ No newline at end of file diff --git a/src/baseWidgetView.ts b/src/baseWidgetView.ts index 5da730c..bf43be0 100644 --- a/src/baseWidgetView.ts +++ b/src/baseWidgetView.ts @@ -167,6 +167,10 @@ export abstract class BaseEChartsWidgetView extends DOMWidgetView { break; } + case 'dispatch_action': { + this._myChart?.dispatchAction(payload); + break; + } default: break; } diff --git a/src/types.ts b/src/types.ts index f9208a7..8c7e18a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -32,7 +32,15 @@ export interface IUnregisterEventMsg { payload: { event: string; id_to_remove?: string[] }; } -export type IKernelMsg = IRegisterEventMsg | IUnregisterEventMsg; +export interface IDispatchActionMsg { + action: 'dispatch_action'; + payload: echarts.Payload; +} + +export type IKernelMsg = + | IRegisterEventMsg + | IUnregisterEventMsg + | IDispatchActionMsg; export interface IEventHandlerParams { action: 'event_handler_params';