Repository: holoviz/panel

Issue:
Echarts not updated when removing a serie
#### Software version info
- python 3.10.12
- panel 1.2.1
- bokeh 3.2.1
- MacOS Ventura 13.5
- Chrome Version 115.0.5790.170 arm64

#### Description 
I have a param `ListSelector`, used to build a panel `CheckBoxGroup`, and an `echart`
The number of series of the echart varies according to the number of values selected in the `CheckBoxGroup`.

When I click new values, a new serie is added, and the plot is properly updated.
But when I unclick an existing value, the plot isn't updated.

More details : 
- in both cases, the echart series are updated. see the reproduction code below.
- having a look at the messages passing through the Websocket, I know that "ModelChanged" messages are received by the browser, *with updated series*. Check screenshots below.

- It's really only *removing* a serie that is failing. Adding series always work. This is illustrated in the video below. For instance, running my reproduction code, run the following sequence : 
  - check 2 (it's updated)
  - check 4 (it's updated)
  - uncheck 4 (it's not updated)
  - check8 (it's updated as expected)

#### Complete, minimal, self-contained example code that reproduces the issue

```python 
import panel as pn
import param

class DemoEchartsBug(pn.viewable.Viewer):

    numbers = param.ListSelector(default=[],
                                objects=[2, 4, 8])

    def __init__(self, **params):
        super().__init__(**params)

        self.cb_group = pn.widgets.CheckBoxGroup.from_param(self.param.numbers)
    
    @param.depends("numbers")
    def plot(self):

        echart_index = list(range(10))
        
        echart_series = [
            {
                "type": "bar",
                "name": str(num),
                "data": [i * num for i in range(10)],
            }
            for num in self.numbers
        ]

        echart_config = {
            "xAxis": [{"type": "category",  "data": echart_index}],
            "yAxis": [{"type": "value"}],
            "series": echart_series,
        }

        echart_pane = pn.pane.ECharts(echart_config,
                                      width=800,
                                      height=400)

        return pn.Column(
                pn.pane.Markdown(f"# numbers : {self.numbers}"),
                echart_pane
        )

    def __panel__(self):

        return pn.Column(
            pn.pane.Markdown(" # Bug with ECharts"),
            self.cb_group,
            pn.layout.Divider(),
            self.plot
        )
```

#### Stack traceback and/or browser JavaScript console output
No console output

#### Screen recording 

https://github.com/holoviz/panel/assets/756464/9b4cfdf5-1414-4b1f-ad7f-c9f88981e0bd



#### Screenshots of the messages in the websocket

- Step 1 : Before removing a serie. There are two series in the echart config
![step 1 - before removing a serie](https://github.com/holoviz/panel/assets/756464/d2e45c03-0850-4211-9c13-21c2c1cde410)

- Step 2 : After removing a serie. There is one serie in the echart config, as it should be. 
![step 2 - after removing a serie](https://github.com/holoviz/panel/assets/756464/a877930c-0898-4d75-9642-e77c88ea6054)




Discussion:
It seems this is a well known, open ECharts issue https://github.com/apache/echarts/issues/6202.

Some workarounds are described in the issue and could explored.

Resolving patch:
diff --git a/panel/models/echarts.py b/panel/models/echarts.py
--- a/panel/models/echarts.py
+++ b/panel/models/echarts.py
@@ -54,6 +54,8 @@ def __js_skip__(cls):
 
     data = Nullable(Dict(String, Any))
 
+    options = Nullable(Dict(String, Any))
+
     event_config = Dict(String, Any)
 
     js_events = Dict(String, List(Any))
diff --git a/panel/pane/echarts.py b/panel/pane/echarts.py
--- a/panel/pane/echarts.py
+++ b/panel/pane/echarts.py
@@ -38,6 +38,12 @@ class ECharts(ModelPane):
     object = param.Parameter(default=None, doc="""
         The Echarts object being wrapped. Can be an Echarts dictionary or a pyecharts chart""")
 
+    options = param.Parameter(default=None, doc="""
+        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 = param.ObjectSelector(default="canvas", objects=["canvas", "svg"], doc="""
        Whether to render as HTML canvas or SVG""")
 


Test patch: