apache / echarts

Apache ECharts is a powerful, interactive charting and data visualization library for browser
https://echarts.apache.org
Apache License 2.0
60.63k stars 19.61k forks source link

Problems when updating chart through echartsInstance.setOption() #6202

Open jeffrey-roosendaal opened 7 years ago

jeffrey-roosendaal commented 7 years ago

When updating the charts through echartsInstance.setOption(), the series are not always correctly updated/drawn.

For example, when I initialize the chart (custom made funnel, but this happens with every chart type) with 3 series, it may look like this:

chart_1

It shows 3 series, which all display correctly. Now, when I create a new chart object with 6 series, and overwrite my current chart, it changes (and animates) to:

chart_2

This, also, looks good. The problem is when updating again, to a chart with less series then the current chart. See what happens when I update the chart to 3 series:

chart_3

It draws the 3 new series over the first old 3 series, and keeps series 4, 5 and 6.


When I output the chart object to console, it shows:

"option": {
    "title": {
        "show": false
    },
    "legend": {
        "show": false,
        "data": [
            {
                "name": "Smartphone",
                "icon": "circle"
            },
            {
                "name": "Desktop",
                "icon": "circle"
            },
            {
                "name": "Tablet",
                "icon": "circle"
            }
        ],
        "selected": {
            "Smartphone": true,
            "Desktop": true,
            "Tablet": true
        }
    },
    "grid": {
        "containLabel": false,
        "top": 0,
        "right": 2,
        "bottom": 20,
        "left": 0,
        "height": 190
    },
    "toolbox": {
        "show": false
    },
    "xAxis": {
        "type": "category",
        "boundaryGap": true,
        "axisLabel": {
            "textStyle": {
                "color": "#444"
            }
        },
        "axisTick": {
            "interval": "auto",
            "lineStyle": {
                "color": "#e5e5e5"
            }
        },
        "axisLine": {
            "lineStyle": {
                "color": "#e5e5e5"
            }
        },
        "splitLine": {
            "show": false,
            "interval": 0,
            "lineStyle": {
                "color": "#e5e5e5"
            }
        },
        "data": [
            {
                "value": "Bezoeken",
                "textStyle": {
                    "align": "center",
                    "fontSize": 10
                }
            },
            {
                "value": "Actief",
                "textStyle": {
                    "align": "center",
                    "fontSize": 10
                }
            },
            {
                "value": "Winkelwagens",
                "textStyle": {
                    "align": "center",
                    "fontSize": 10
                }
            },
            {
                "value": "Bestellingen",
                "textStyle": {
                    "align": "center",
                    "fontSize": 10
                }
            }
        ]
    },
    "yAxis": [
        {
            "boundaryGap": [
                0,
                "10%"
            ],
            "type": "value",
            "show": false,
            "min": 0,
            "axisLabel": {
                "textStyle": {
                    "color": "#444",
                    "fontSize": 10
                }
            },
            "axisTick": {
                "lineStyle": {
                    "color": "#e5e5e5"
                }
            },
            "axisLine": {
                "lineStyle": {
                    "show": false,
                    "color": "#fff"
                }
            },
            "splitLine": {
                "interval": 0,
                "show": false,
                "lineStyle": {
                    "color": "#e5e5e5"
                }
            },
            "data": [
                "Smartphone",
                "Desktop",
                "Tablet"
            ]
        }
    ],
    "series": [
        {
            "name": "Smartphone",
            "type": "bar",
            "stack": "metric",
            "label": {
                "normal": {
                    "show": true,
                    "position": "top",
                    "offset": [
                        0,
                        -10
                    ],
                    "textStyle": {
                        "color": "#444"
                    }
                }
            },
            "itemStyle": {
                "normal": {
                    "color": "#1AB394"
                }
            },
            "data": [
                185,
                89,
                8,
                0
            ]
        },
        {
            "name": "Desktop",
            "type": "bar",
            "stack": "metric",
            "label": {
                "normal": {
                    "show": true,
                    "position": "top",
                    "offset": [
                        0,
                        -10
                    ],
                    "textStyle": {
                        "color": "#444"
                    }
                }
            },
            "itemStyle": {
                "normal": {
                    "color": "#23C6C8"
                }
            },
            "data": [
                104,
                51,
                9,
                1
            ]
        },
        {
            "name": "Tablet",
            "type": "bar",
            "stack": "metric",
            "label": {
                "normal": {
                    "show": true,
                    "position": "top",
                    "offset": [
                        0,
                        -10
                    ],
                    "textStyle": {
                        "color": "#444"
                    }
                }
            },
            "itemStyle": {
                "normal": {
                    "color": "#F8AC59"
                }
            },
            "data": [
                38,
                25,
                4,
                0
            ]
        }
    ],
    "tooltip": {
        "trigger": "axis",
        "position": "inside",
        "axisPointer": {
            "shadowStyle": {
                "color": "#000",
                "shadowBlur": 0,
                "opacity": 0.07
            },
            "type": "shadow"
        },
        "textStyle": {
            "fontFamily": "Roboto"
        },
        "extraCssText": "padding: 8px 15px; font-size: 13px;"
    }
}

There is not a single mention of "Motorola", "Huawei" or "Overig" in my code, but, when I add console.log(params) to charts.tooltip.formatter, it shows:

[
    {
        "componentType": "series",
        "componentSubType": "bar",
        "seriesType": "bar",
        "seriesIndex": 0,
        "seriesId": "\u0000Smartphone\u00000",
        "seriesName": "Smartphone",
        "name": "Bezoeken",
        "dataIndex": 0,
        "data": 185,
        "value": 185,
        "color": "#1AB394",
        "marker": "<span style=\"display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:#1AB394;\"></span>",
        "$vars": [
            "seriesName",
            "name",
            "value"
        ],
        "axisDim": "x",
        "axisIndex": 0,
        "axisType": "xAxis.category",
        "axisId": "\u0000\u0000-\u00000",
        "axisValue": "Bezoeken",
        "axisValueLabel": "Bezoeken"
    },
    {
        "componentType": "series",
        "componentSubType": "bar",
        "seriesType": "bar",
        "seriesIndex": 1,
        "seriesId": "\u0000Desktop\u00000",
        "seriesName": "Desktop",
        "name": "Bezoeken",
        "dataIndex": 0,
        "data": 104,
        "value": 104,
        "color": "#23C6C8",
        "marker": "<span style=\"display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:#23C6C8;\"></span>",
        "$vars": [
            "seriesName",
            "name",
            "value"
        ],
        "axisDim": "x",
        "axisIndex": 0,
        "axisType": "xAxis.category",
        "axisId": "\u0000\u0000-\u00000",
        "axisValue": "Bezoeken",
        "axisValueLabel": "Bezoeken"
    },
    {
        "componentType": "series",
        "componentSubType": "bar",
        "seriesType": "bar",
        "seriesIndex": 2,
        "seriesId": "\u0000Tablet\u00000",
        "seriesName": "Tablet",
        "name": "Bezoeken",
        "dataIndex": 0,
        "data": 38,
        "value": 38,
        "color": "#F8AC59",
        "marker": "<span style=\"display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:#F8AC59;\"></span>",
        "$vars": [
            "seriesName",
            "name",
            "value"
        ],
        "axisDim": "x",
        "axisIndex": 0,
        "axisType": "xAxis.category",
        "axisId": "\u0000\u0000-\u00000",
        "axisValue": "Bezoeken",
        "axisValueLabel": "Bezoeken"
    },
    {
        "componentType": "series",
        "componentSubType": "bar",
        "seriesType": "bar",
        "seriesIndex": 3,
        "seriesId": "\u0000Motorola\u00000",
        "seriesName": "Motorola",
        "name": "Bezoeken",
        "dataIndex": 0,
        "data": 7,
        "value": 7,
        "color": "#ED5565",
        "marker": "<span style=\"display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:#ED5565;\"></span>",
        "$vars": [
            "seriesName",
            "name",
            "value"
        ],
        "axisDim": "x",
        "axisIndex": 0,
        "axisType": "xAxis.category",
        "axisId": "\u0000\u0000-\u00000",
        "axisValue": "Bezoeken",
        "axisValueLabel": "Bezoeken"
    },
    {
        "componentType": "series",
        "componentSubType": "bar",
        "seriesType": "bar",
        "seriesIndex": 4,
        "seriesId": "\u0000Huawei\u00000",
        "seriesName": "Huawei",
        "name": "Bezoeken",
        "dataIndex": 0,
        "data": 4,
        "value": 4,
        "color": "#1C84C6",
        "marker": "<span style=\"display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:#1C84C6;\"></span>",
        "$vars": [
            "seriesName",
            "name",
            "value"
        ],
        "axisDim": "x",
        "axisIndex": 0,
        "axisType": "xAxis.category",
        "axisId": "\u0000\u0000-\u00000",
        "axisValue": "Bezoeken",
        "axisValueLabel": "Bezoeken"
    },
    {
        "componentType": "series",
        "componentSubType": "bar",
        "seriesType": "bar",
        "seriesIndex": 5,
        "seriesId": "\u0000Other\u00000",
        "seriesName": "Other",
        "name": "Bezoeken",
        "dataIndex": 0,
        "data": 9,
        "value": 9,
        "color": "#dedede",
        "marker": "<span style=\"display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:#dedede;\"></span>",
        "$vars": [
            "seriesName",
            "name",
            "value"
        ],
        "axisDim": "x",
        "axisIndex": 0,
        "axisType": "xAxis.category",
        "axisId": "\u0000\u0000-\u00000",
        "axisValue": "Bezoeken",
        "axisValueLabel": "Bezoeken"
    }
]

So, they are not in my chart object, but Echarts still draws them, and as you can see, they still exist in the tooltip params.

The chart does update well when using chartInstance.clear() before chartInstance.setOption(), but then I'll lose all the nice transitions and animations, which make ECharts look so beautiful.

Bkengs commented 7 years ago

I have the same problem recently , i solved it by set the series's data = null which you do not want. Also you can try it setOption(option, true)

jeffrey-roosendaal commented 7 years ago

Thanks for your suggestions!

Setting data = null on all the previous series may lead to a lot of code rewriting on my part, which is not my prefered option.

And, using setOption(option, true), is the same as calling refresh(), which removes the transition animations, which is what I like so much about ECharts. But for now, I'll go with setOption(option, true) when changing data, until the ECharts team comes with a solution or fix. Thanks!

sorenhoyer commented 6 years ago

This is still a problem. And a very annoying one. I'd call it a bug rather than an enhancement, since it's a very big problem when dealing with realtime data (calling setOption frequently) and building the chart from data in React. :)

skraemer-eis commented 6 years ago

I have the same problems and I agree with @sorenhoyer: I would also call it a bug. It should be possible to delete series with setOptions

anasanzari commented 6 years ago

+1

tehZevo commented 6 years ago

+1

pchaganti commented 6 years ago

👍

pchaganti commented 6 years ago

setOption() is still leaving the old data on the chart BTW.

ghost commented 6 years ago

+1

sys4soft commented 6 years ago

Until this is solved, I've come with the radical solution of clearing the chart and "recreate" it again. Not a problem for me, since my char is only updated after I submit a form in the same page and the graphic only comes visible after a success ajax call.

Basically: All echart construction inside a function (EchartConstruction); When ajax is called and have a success return: [instance].clear() and execute EchartConstruction function Then, set the axis and series.

eviltomato commented 6 years ago

I have the same issue with bar chart

mishantidev commented 6 years ago

+1!

VictorChen commented 6 years ago

This sounds like a bug to me, if you can add a series via setOption, then you should be able to remove a series as well. Here's a quick reproducer of this bug:

http://jsfiddle.net/douykvbc/

Clicking on One Line and then Two Lines => works

Clicking on Two Lines and then One Line => doesn't work

VictorChen commented 6 years ago

@100pah I've noticed you added the new-feature label, but I believe this is a bug. Please see my post above.

sswaroopk commented 6 years ago

+1

emailhy commented 6 years ago

+1

HugoMitsumori commented 6 years ago

+1

satonreb commented 6 years ago

Same issue here. To resolve it I set notMerge to true in setOption() as per ECharts Documentation

DavidDuranPerez commented 6 years ago

Same issue here. To resolve it I set notMerge to true in setOption() as per ECharts Documentation

It does not solve the problem for me.

melanke commented 5 years ago

This is a bug

rredondog commented 5 years ago

I've solved it creating two functions one only with myChart.clear and another for draw all the chart and allways first call de function wich clear the chart and after the ones for draw it.

melanke commented 5 years ago

I solved it by storing the options in a variable and doing the merge by myself :/

klausb commented 5 years ago

@melanke

I solved it by storing the options in a variable and doing the merge by myself :/

But you still nee the clear() call before setting your merged result, correct?

klausb commented 5 years ago

To me this is a serious defect, as it kills most of the animation feature from echarts, when morphing across changes. Doing a clear() inbetween all updates is destroying most of the nice rendering effects.

ckz8780 commented 5 years ago

Nearly two years and still no response to this. This isn't an "enhancement" ... it's an extremely annoying and show stopping bug. Any idea on when this will be resolved? All these hacky solutions are mediocre at best and leave the potential for a future update to Echarts that fixes the problem to break the solution users have come up with on their own.

klausb commented 5 years ago

@ckz8780 Fully agree. Maybe someone can dig into the code, fix it and submit a pull request.

ckz8780 commented 5 years ago

For what it's worth, I have been able to (somewhat) work around it and maintain animations by using dispatchAction() to unselect the legend items of the series I'm trying to remove. It works from a display standpoint, but still very annoying because the legend items are still shown in the legend. Anyway just thought I would post my workaround to give others one more idea until it's resolved.

jbadilla commented 5 years ago

This needs to be fixed as soon as possible, in order to maintain the integrity of what makes eCharts the best alternative for any sort of graphing library.

behrouz-psh commented 5 years ago

come on after 2 years still not fixed? I need to remove the series without refreshing the chart

jbadilla commented 5 years ago

Are people here using React with eCharts?

BEGEMOT9I commented 5 years ago

@jbadilla yes, i am.

jonalxh commented 5 years ago

I've solved it just clearing the chart variable before passing the options:

var myChart = echarts.init(document.getElementById("bar-chart"));
myChart.clear();
myChart.setOption(option, true), $(function () { ... }

It works nice.

klausb commented 5 years ago

@jonalxh, but this will kill the animation between the states. I use the same approach, but it would be great if the removal of a line from a multiline chart would not force me to rmove all and then to add n-1 again.

jeffersonswartz commented 5 years ago

Same issue here. To resolve it I set notMerge to true in setOption() as per ECharts Documentation

Setting True Fixes it. It preserves the transition animation too. http://jsfiddle.net/jeffersonswartz/r6vuo0pq/1/

jmarceli commented 5 years ago

This bug seems to be related to sampling option. If it is set to any value e.g. max or average or any other you will get a visual bug when the number of points will trigger sampling after changing plotted data.

gosk8 commented 5 years ago

Actually we can't setOptions() fluently by using noMerge=true even chart.clear()cause it will resets the legends we selected before.

huseyinozgul commented 5 years ago

I solved this problem in React. chart.setOption({},true}); chart.setOption(option,true);

qcgm1978 commented 4 years ago

@melanke

I solved it by storing the options in a variable and doing the merge by myself :/

But you still nee the clear() call before setting your merged result, correct?

clear() is enough and elegant

Rushan4eg commented 4 years ago

Still a problem, especially on vue.js... Someone maybe can help with fix for vue.js?

melanke commented 4 years ago
get chartOptions() {
    return {
      grid: { right: 25, left: '10%', top: '5%' },
      tooltip: { trigger: 'axis' },
      textStyle: {
        color: !this.isPrinting ? '#666' : '#000',
      },
      xAxis: {
        type: 'category',
      },
      yAxis: {
        type: 'value',
        axisLine: { show: false },
        splitLine: { lineStyle: { opacity: 0.1 } },
        boundaryGap: false,
      },
      color: this.value.orderedColors,
    }
  }

  @Watch('myThing')
  updateChartData() {
    if (!this.echart) {
      return
    }

    const option = {
      ...this.chartOptions,
      dataset: {
        source: this.value.chartData,
      },
      series,
      dataZoom: this.dataZoom,
      graphic: this.buildChartGraphics(),
    }

    this.echart.setOption(option, true)
  }

@Rushan4eg I am using Vue as well, but I don't think it makes any difference

peder1001 commented 4 years ago

In Angular using ngx-echarts. I solved it temporarily as follows.

First get a hold of your echarts instance. You can do this in your markup. Add "chartInit" and reference your desired function

<div echarts [options]="this.options" [merge]="updateOptions" (chartInit)="this.onChartInit($event)" class="chart"></div>

In your ts:

onChartInit(ec) {
    this.echartsInstance = ec;
    // do whatever you want here
}

So now this.echartsInstance can be used.

Then when updating your chart (in my case in the updateOptions function), I just added:

if (this.echartsInstance) {
      // Temp fix for bug, see: https://github.com/apache/incubator-echarts/issues/6202
      this.echartsInstance.clear();
      this.echartsInstance.setOption(this.options);
}
PROLANGtest commented 4 years ago

SOLVED in Angular 9 - but I did it differently - you can update the chart with echarts.init(this.MyChart);
The problem seems to stem from the lag between the time the DOM element actually renders or fetches the element.

  1. First get the parent.
  2. Wait a little - get the canvas
  3. Re-Initiate the canvas
  4. setOption

CODE:

let parent = document.getElementsByClassName('gaugeChart')[0]; setTimeout(() => { this.MyChartCanvas = parent.querySelector('canvas'); }, 100);

  echarts.init(this.MyChartCanvas);

  let myChart = echarts.getInstanceByDom(this.MyChartCanvas);
  myChart.setOption(this.doughnutChartOption, true);
Aman-Kaushik13 commented 4 years ago

I am using the Flutter echarts package.... in the docs it says that its reactive but the chart doesn't change when I add a series in options.... I have to hot restart for the chart to appear, I also can't add dynamic data...... is there setOptions for flutter library as well??

diogns commented 3 years ago

I solved this for React and only set "notMerge" to true.

<ReactECharts option={options} opts={{ renderer: 'svg' }} notMerge={true} />

symlons commented 3 years ago

I tried all the suggested hacks listed above but I am getting the same error. I am using socket.io to update the data but I have no idea how to approach this issue after trying the suggested hacks. Any suggestions what the underlying cause of this problem might by?

mathias22osterhagen22 commented 3 years ago

This issue has been a high priority since 2019.... please...

I fixed it in vue-echarts like this:

 fixIssue6202Echart() {
   //Fix: https://github.com/apache/echarts/issues/6202
   if (this.$refs.yourChart) this.$refs.yourChart.setOption(this.datas, true);
  }
T0miii commented 3 years ago

So is there a recommended way by now to remove a Series from the Chart, without losing every other config option?

LeaVerou commented 2 years ago

Just ran into a similar bug when changing axis names and using setOption(). Here's a reduced testcase: https://codepen.io/leaverou/pen/xxLBMJJ?editors=0010

pissang commented 2 years ago

Sorry to be late here. 5.0 introduces a new parameter replaceMerge that can remove series or any component without loosing interaction states from other components, like legend selection.

https://echarts.apache.org/en/api.html#echartsInstance.setOption

Example usage:

myChart.setOption({
  series: newSeriesHere
}, { replaceMerge: ['series'] })
mpope9 commented 2 years ago

@pissang That worked for me, thanks!