Open this notebook in Jupyterlite | Download this notebook from GitHub (right-click to download).

import panel as pn

The ECharts pane renders Apache ECharts and pyecharts plots inside Panel. Note that to use the ECharts pane in the notebook the Panel extension has to be loaded with ‘echarts’ as an argument to ensure that echarts.js is initialized.


For details on other options for customizing the component see the layout and styling how-to guides.

  • object (dict): An ECharts plot specification expressed as a Python dictionary, which is then converted to JSON. Or a pyecharts chart like pyecharts.charts.Bar.

  • options (dict): An optional dict of options passed to Echarts.setOption. Allows to fine-tune the rendering behavior. For example, you might want to use options={ "replaceMerge": ['series'] }) when updating the objects with a value containing a smaller number of series.

  • renderer (str): Whether to render with HTML ‘canvas’ (default) or ‘svg’

  • theme (str): Theme to apply to plots (one of ‘default’, ‘dark’, ‘light’)

Lets try the ECharts pane support for ECharts specs in its raw form (i.e. a dictionary), e.g. here we declare a bar plot:

echart_bar = {
    'title': {
        'text': 'ECharts entry example'
    'tooltip': {},
    'legend': {
    'xAxis': {
        'data': ["shirt","cardign","chiffon shirt","pants","heels","socks"]
    'yAxis': {},
    'series': [{
        'name': 'Sales',
        'type': 'bar',
        'data': [5, 20, 36, 10, 10, 20]
echart_pane = pn.pane.ECharts(echart_bar, height=480, width=640)

Like all other panes, the ECharts pane object can be updated, either in place and triggering an update:

echart_bar['series'] = [dict(echart_bar['series'][0], type='line')]

Vega specification can also be responsively sized by declaring the width or height to match the container:

responsive_spec = dict(echart_bar, responsive=True)

pn.pane.ECharts(responsive_spec, height=400)

The ECharts pane also has support for pyecharts. For example, we can pass a pyecharts.charts.Bar chart directly the ECharts pane.

from pyecharts.charts import Bar

bar1 = pn.widgets.IntSlider(start=1, end=100, value=50)
bar2 = pn.widgets.IntSlider(start=1, end=100, value=50)

def plot(bar1, bar2):
    my_plot= (Bar()
        .add_xaxis(['Helicoptors', 'Planes'])
        .add_yaxis('Total In Flight', [bar1, bar2])
    return pn.pane.ECharts(my_plot, width=500, height=250)
    pn.Column(bar1, bar2),
    pn.bind(plot, bar1, bar2),

The ECharts library supports a wide range of chart types and since the plots are expressed using JSON datastructures we can easily update the data and then emit change events to update the charts:

gauge = {
    'tooltip': {
        'formatter': '{a} <br/>{b} : {c}%'
    'series': [
            'name': 'Gauge',
            'type': 'gauge',
            'detail': {'formatter': '{value}%'},
            'data': [{'value': 50, 'name': 'Value'}]
gauge_pane = pn.pane.ECharts(gauge, width=400, height=400)

slider = pn.widgets.IntSlider(value=50, start=0, end=100)

slider.jscallback(args={'gauge': gauge_pane}, value="""[0].data[0].value = cb_obj.value

pn.Column(slider, gauge_pane)


The EChart object allows you to listen to any event defined in the Javascript API, either by listening to the event in Python using the on_event method or by triggering a Javascript callback with the js_on_event method.

For details on what events you can ECharts events documentation.


Let us start with a simple click event we want to listen to from Python. To add an event listener we simple call the on_event method with the event type (in this case ‘click’) and our Python handler.

echart_pane = pn.pane.ECharts(echart_bar, height=480, width=640)
json = pn.pane.JSON()

def callback(event):
    json.object =

echart_pane.on_event('click', callback)

pn.Row(echart_pane, json)

Try clicking on a point on the line. When inspecting the json.object after a click you should see something like this:

{'componentType': 'series',
 'componentSubType': 'line',
 'componentIndex': 0,
 'seriesType': 'line',
 'seriesIndex': 0,
 'seriesId': '\x00Sales\x000',
 'seriesName': 'Sales',
 'name': 'shirt',
 'dataIndex': 0,
 'data': 5,
 'value': 5,
 'color': '#5470c6',
 'dimensionNames': ['x', 'y'],
 'encode': {'x': [0], 'y': [1]},
 '$vars': ['seriesName', 'name', 'value'],
 'event': {'detail': 1,
  'altKey': False,
  'button': 0,
  'buttons': 0,
  'clientX': 507,
  'clientY': 911,
  'ctrlKey': False,
  'metaKey': False,
  'pageX': 507,
  'pageY': 911,
  'screenX': 3739,
  'screenY': 762,
  'shiftKey': False,
  'target': {'boundingClientRect': {}},
  'currentTarget': {'boundingClientRect': {}},
  'relatedTarget': None},
 'type': 'click'}

To restrict what types of objects a particular event applies to you can also provide a query argument to the on_event method. The format of the query should be mainType or mainType.subType, such as:

  • 'series': Fire event when clicking on data series

  • 'series.line': Fire event only when clicking on a line data series.

  • 'dataZoom': Fire event when clicking on zoom.

  • 'xAxis.category': Fire event when clicking on a category on the xaxis.


The same concepts apply in Javascript, however here we pass in Javascript code a JS snippet. The namespace allows you to access the event data cb_data and the ECharts chart itself as cb_obj. In this way you have access to the event and can manipulate the plot yourself:

echart_pane = pn.pane.ECharts(echart_bar, height=480, width=640)

echart_pane.js_on_event('click', 'alert(`Clicked on point: ${cb_data.dataIndex}`)')


If you want to modify another object in response to an event triggered on the chart you can pass additional objects to the json_on_event method. The corresponding Bokeh model will then be made available in the callback. As an example here we make the JSON pane available so that we can update it on a click event:

echart_pane = pn.pane.ECharts(echart_bar, height=480, width=640)
json = pn.pane.JSON()

echart_pane.js_on_event('click', """
event = {...cb_data}
delete event.event
json.text = JSON.stringify(event)
""", json=json)

pn.Row(echart_pane, json)


The EChart pane exposes a number of options which can be changed from both Python and Javascript. Try out the effect of these parameters interactively:

pn.Row(gauge_pane.controls(jslink=True), gauge_pane)

Open this notebook in Jupyterlite | Download this notebook from GitHub (right-click to download).