valor-software / ng2-charts

Beautiful charts for Angular based on Chart.js
http://valor-software.github.io/ng2-charts/
MIT License
2.34k stars 572 forks source link

Data Decimation not working #1383

Open noobnoobdc137 opened 2 years ago

noobnoobdc137 commented 2 years ago

Reproduction of the problem

TS file

import { Component, ViewChild } from '@angular/core';
import { BaseChartDirective } from 'ng2-charts';
import 'chartjs-adapter-moment';

function randNumGen(max) {
  return Math.floor((Math.random() * max) + 1)
}

const NUM_POINTS = 10000;

const START = 1617235200000;
const POINT_DATA = [];

for (let i = 0; i < NUM_POINTS; ++i) {
  const max = Math.random() < 0.001 ? 100 : 20;
  const randNumber = randNumGen(max)
  POINT_DATA.push({ x: START + i * 30000, y: randNumber });
}

@Component({
  selector: 'app-line-chart',
  templateUrl: './line-chart.component.html',
  styleUrls: ['./line-chart.component.css']
})
export class LineChartComponent {

  @ViewChild(BaseChartDirective) chart?: BaseChartDirective;

  data = {
    datasets: [
      {
        borderColor: "red",
        borderWidth: 1,
        data: POINT_DATA,
        label: "Large Dataset",
        radius: 0,
      },
    ],
  };

  plugins = {
    decimation: {
      enabled: false,
      algorithm: 'min-max',
    },
  }

  options = {
    animation: false,
    parsing: false,

    interaction: {
      mode: "nearest",
      axis: "x",
      intersect: false,
    },

    scales: {
      x: {
        type: "time",
        ticks: {
          source: "auto",
          maxRotation: 0,
          autoSkip: true,
        },
      },
    },
  }

  public buttonOnclick() {
    this.plugins.decimation.enabled = true;
    this.plugins.decimation.algorithm = 'min-max';

    this.chart.chart.update();
  }
}

Template HTML

<div class="flex">
  <div class="flex-item">
    <div style="display: block">
      <canvas
        baseChart
        width="400"
        height="400"
        [data]="data"
        [options]="options"
        [type]="'line'"
        [plugins]="plugins"
      ></canvas>
    </div>
  </div>
  <button (click)="buttonOnclick()">
    Decimation {{ plugins.decimation.enabled }}
  </button>
</div>

Versions

Package Version
chart.js 3.7.1
ng2-charts 3.0.8
chartjs-adapter-date-fns 2.0.0
chartjs-adapter-luxon 1.1.0
chartjs-adapter-moment 1.0.0

Angular Version: 12.1.1

tru-koto commented 2 years ago

@noobnoobdc137 - You mind putting this in a stackblitz or codesandbox for all of us?

lunar-safari commented 2 years ago

Not working for me either. Ideally, a simple way to have it would be;

public lineChartOptions: ChartConfiguration['options'] = {
    elements: {
      line: {
        tension: 0.5
      }
    },
    scales: {
      x: {},
      'y-axis-0':
      {
        position: 'left',
        reverse: this.reverseInput
      },
    },
    plugins: {
      legend: { display: true },
      decimation: {
        enabled: true,
        algorithm: 'lttb',
        samples:50
      },
    }

  };

And pass those option to the chart

  <canvas baseChart
          [data]="lineChartData"
          [options]="lineChartOptions"
          [type]="lineChartType"></canvas>

My line chart has too many points crowding the line. It would be great to 'thin the herd' with this simple plugin.

santam85 commented 2 years ago

Probably decimation needs a re-render of the chart? Can you try using this.chart.render(); or setting the decimation.enabled to true from the start to see if it makes any difference?

nicolas-cusan commented 1 year ago

Did anybody get this to work? I am having the same problem. My data gets rendered but decimation is not applied.

jmtimper commented 1 year ago

Any updates on this? I'm running into a similar issue

nicolas-cusan commented 1 year ago

I did get it to work, but it took some fiddling. I preprocessed my data to not need any interpolation by converting my x axis from an ISO Date to Milliseconds, that did the trick. I used luxon and the luxon chart.js adapter for the conversion and formatting.

This is the code I applied to activate decimation:

plugins: {
  // ...
  decimation: {
    algorithm: 'lttb',
    enabled: true,
    samples: 100,
    threshold: 40,
  },
 // ...
}

For display purposes I formatted the date like this:

scales: {
  x: {
    type: 'time',
    time: {
      displayFormats: {
        month: 'MMM ‘yy',
      },
    },
  },
  // ...
}

Hope it helps.

just-website commented 1 month ago

Hope it helps.

Thank you. I realized that threshold must be specified for small values. In my case it's

{
  ...
  decimation: {
    algorithm: 'lttb',
    enabled: true,
    samples: 25,
    threshold: 25,
  }
}

and it didn't work unless explicitly stated