Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding and removing chart series confuses Highcharts #1

Open
metaperl opened this issue Oct 12, 2023 · 6 comments
Open

Adding and removing chart series confuses Highcharts #1

metaperl opened this issue Oct 12, 2023 · 6 comments
Assignees
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@metaperl
Copy link

Description

image

In the screenshot attached you see:

  1. "bob" and "john" in the legend of the graph
  2. "alice" and "john" in the chips of the multi-select

this is a bug because they should be the same.

how to reproduce

  1. run the program below
  2. repeatedly select and de-select a certain element (e.g. select and de-select 'alice')
  3. after three repetitions of step 2, a mismatch will occur between the legend and the chips displayed.

This video shows the same thing. Regrettably, the capture window did not capture the deselections and selections of the same element - https://www.youtube.com/watch?v=KOKuhgMA9dk

from nicegui import ui

# initial data
data1 = {'name': 'alice', 'data': [31, 148, 33, 68, 75, 43]}
data2 = {'name': 'bob', 'data': [3, 28, 7, 5, 8, 3]}
data3 = {'name': 'john', 'data': [11, 42, 10, 18, 9, 0]}

all_data = dict(alice=data1, bob=data2, john=data3)

print(f"keys = {list(all_data.keys())}")

chart = None
chart_options = {
    'chart': {
        'type': 'spline',
    },
    'legend': {
        'enabled': True,
        'layout': 'vertical',
        'align': 'right',
        'verticalAlign': 'middle',
    },
    'navigator': {
        'enabled': True
    },
    'scrollbar': {
        'enabled': False
    },
    'series': [data1, data2, data3]
}


def plot():
    global chart, chart_options
    chart = ui.chart(chart_options, type='stockChart', extras=['stock'])


def update_chart(selections):
    global chart

    datums = [all_data[selection] for selection in selections]


    chart.options['series'] = datums
    chart.update()



plot()
ui.select(list(all_data.keys()), multiple=True, value=list(all_data.keys()),
          label='with chips', on_change=lambda e: update_chart(e.value)
          ).classes('w-64').props('use-chips')

ui.run(reload=False)
@falkoschindler
Copy link
Contributor

Wow, this is strange. I boiled it down to this:

def toggle():
    chart.options['series'] = [{'data': [1]}, {'data': [2]}] if len(chart.options['series']) == 1 else [{'data': [1]}]
    chart.update()

chart = ui.chart({'series': [{'data': [1]}]})
ui.button('Toggle', on_click=toggle)

Even though the options always contain a data point at 1, toggling multiple times leads to a single point at 2.

I wonder if we can reproduce the problem with a pure Highcharts example without NiceGUI...

@falkoschindler
Copy link
Contributor

No, without NiceGUI the example is working:

<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container"></div>
<button onclick="toggle()">Toggle</button>
<script>
  let chart = Highcharts.chart("container", { series: [{ data: [1] }] });
  function toggle() {
    if (chart.series.length === 1) {
      chart.addSeries({ data: [2] });
    } else {
      chart.series[1].remove();
    }
  }
</script>

Now I'm pretty sure the issue is caused by update_chart() in chart.js which follows a pretty naive heuristic to add and remove series:
https://github.com/zauberzeug/nicegui/blob/eea7d8d4ce91be270edfacb29e26b385ba447d0f/nicegui/elements/chart.js#L40-L52

@falkoschindler falkoschindler self-assigned this Oct 12, 2023
@falkoschindler falkoschindler added the bug Something isn't working label Oct 12, 2023
@falkoschindler falkoschindler changed the title repeated selection and deselection of a multi-select item leads to mismatch of legend and chips Adding and removing chart series confuses Highcharts Oct 12, 2023
@falkoschindler
Copy link
Contributor

Minimum reproduction without NiceGUI (but with the same update algorithm from chart.js):

<html>
  <head>
    <script src="https://code.highcharts.com/highcharts.js"></script>
  </head>
  <body>
    <div id="container"></div>
    <button onclick="toggle()">Toggle</button>
    <script>
      let options = { series: [{ data: [1] }] };
      let chart = Highcharts.chart("container", options);
      let seriesCount = options.series ? options.series.length : 0;

      function toggle() {
        if (options.series.length === 1) {
          options.series.push({ data: [2] });
        } else {
          options.series.pop();
        }
        update();
      }

      function update() {
        while (seriesCount > options.series.length) {
          chart.series[0].remove();
          seriesCount--;
        }
        while (seriesCount < options.series.length) {
          chart.addSeries({}, false);
          seriesCount++;
        }
        chart.update(options);
      }
    </script>
  </body>
</html>

The question is, how to improve the update() function.

@falkoschindler falkoschindler added the help wanted Extra attention is needed label Oct 13, 2023
@falkoschindler
Copy link
Contributor

I created a test page for manipulating Highcharts options:

test.html
<html>
  <head>
    <script src="https://code.highcharts.com/highcharts.js"></script>
  </head>
  <body>
    <div id="container"></div>
    <button onclick="insert_low()">Insert low</button>
    <button onclick="insert_high()">Insert high</button>
    <button onclick="remove_low()">Remove low</button>
    <button onclick="remove_high()">Remove high</button>
    <button onclick="reset()">Reset</button>
    <button onclick="clear_all()">Clear</button>
    <script>
      let options = { series: [{ data: [0] }, { data: [1] }, { data: [2] }] };
      let seriesCount = options.series.length;
      let chart = Highcharts.chart("container", options);

      function insert_low() {
        options.series.unshift({ data: [options.series[0].data[0] - 1] });
        update();
      }

      function insert_high() {
        options.series.push({ data: [options.series[options.series.length - 1].data[0] + 1] });
        update();
      }

      function remove_low() {
        options.series.shift();
        update();
      }

      function remove_high() {
        options.series.pop();
        update();
      }

      function reset() {
        options.series = [{ data: [0] }];
        update();
      }

      function clear_all() {
        options.series = [];
        update();
      }

      function update() {
        while (seriesCount > options.series.length) {
          chart.series[0].remove();
          seriesCount--;
        }
        while (seriesCount < options.series.length) {
          chart.addSeries({}, false);
          seriesCount++;
        }
        chart.update(options);
      }
    </script>
  </body>
</html>

Currently all series collapse into a point at -1 when clicking "insert low".
And a lengthy discussion with ChatGPT about improving the update() function wasn't successful.

@falkoschindler
Copy link
Contributor

I still don't have a good solution for fixing this issue.
In order to focus on a quick release of upcoming version 1.4, I'll postpone this one to 1.4.1.

@falkoschindler
Copy link
Contributor

I'm currently thinking about how to solve an update like this:

<html>
  <head>
    <script src="https://code.highcharts.com/highcharts.js"></script>
  </head>
  <body>
    <div id="container"></div>
    <button onclick="add()">Add</button>
    <script>
      let options = { series: [{ data: [1] }, { data: [2] }, { data: [3] }] };
      let chart = Highcharts.chart("container", options);

      function add() {
        options.series.unshift({ data: [0] });
        chart.update(options);
      }
    </script>
  </body>
</html>

The chart simply collapses, which doesn't make any sense and looks like a bug in Highcharts. But it's hard to find a related bug report. This one might be relevant, maybe not. With 1.1K open and 13K closed issues it's hard to tell if this behavior is known and/or already worked on.

By the way: A conversation with their AI didn't yield much insight.

@falkoschindler falkoschindler transferred this issue from zauberzeug/nicegui Nov 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants