SciChart® the market leader in Fast WPF Charts, WPF 3D Charts, iOS Chart, Android Chart and JavaScript Chart Components

Answered
1
0

I am using SciChart with Next.js to create a real-time updated line chart. It works fine if there is 1 trace running with 130k datapoints. But when there are 4 traces (each with 130k datapoints) running in the chart, there is performance issue. After running for a while, this error is showing in the browser console:

“RangeError: Failed to execute ‘texImage2D’ on ‘WebGL2RenderingContext’: The ArrayBuffer/ArrayBufferView size exceeds the supported range.”

I tried to optimize the chart by following this page, but it doesn’t help on the lag issue.
https://www.scichart.com/documentation/js/current/Performance%20Tips.html

Here are my codes for updating the chart data:

if (SciChartSurface.renderableSeries.get(trace_num)) {
    SciChartSurface.renderableSeries.get(trace_num).dataSeries = new XyDataSeries(WasmContext, { xValues: dataX, yValues: dataY });
} else {
    const lineSeries = new FastLineRenderableSeries(WasmContext);
    lineSeries.strokeThickness = 1;
    lineSeries.stroke = tracesInfoRef[trace_num].color;
    lineSeries.dataSeries = new XyDataSeries(WasmContext, { xValues: dataX, yValues: dataY, dataIsSortedInX: true, dataEvenlySpacedInX: true, containsNaN: false });
    SciChartSurface.renderableSeries.add(lineSeries);
}

Can SciChart perform well with multiple traces which total datapoints larger than 500k? How can I fix the texImage2D error ?

Version
2.2.2415
Images
  • You must to post comments
Best Answer
1
0

Hi Kelly,

From first glance I notice that you do this in your code:

traceNumArr.forEach((tnum) => {
    if (sciChartSurfaceRef.current.renderableSeries.get(tnum)) {
        console.time("create new series with Flags");
        sciChartSurfaceRef.current.renderableSeries.get(tnum).dataSeries = new XyDataSeries(wasmContextRef.current, { xValues: dataX, yValues: newData });
        console.timeEnd("create new series with Flags");
    }
});

Creating an entirely new DataSeries every time the data changes could be inefficient. DataSeries has a number of functions to allow updates, including DataSeries.Update(), Remove(), RemoveAt(), Clear(), Append(), Insert()

Also, the old DataSeries needs to be deleted when you no longer use it. If you don’t do this you will run out of WebAssembly memory (memory leak in Wasm).

See these pages in our documentation

The DataSeries API

Deleting a DataSeries 
  // Calling delete on a DataSeries releases its webassembly memory. This series is no longer usable
  xyDataSeries.delete();
  
  // Calling delete on a RenderableSeries will delete both the RenderableSeries and its dataseries.
  // This series is no longer usable
  const lineSeries = new FastLineRenderableSeries(wasmContext);
  lineSeries.delete();
  
  // Calling delete on a SciChartSurface will delete and free memory on all elements in this chart
  // This chart is no longer usable.
  const { wasmContext, sciChartSurface } = await SciChartSurface.create(divElementId);
  sciChartSurface.delete();
  Failing to call IDeletable.delete() on a DataSeries or it's parent SciChartSurface when it is no longer needed can result in a memory leak.
  
  To simplify your code, if you do not change DataSeries instances, you can call delete on the parent SciChartSurface once. This will delete all child objects that hold native memory.
  

Manipulating DataSeries Data for Dynamic Updates

Append, Update, Insert, Remove    
  const xyDataSeries = new XyDataSeries(wasmContext);
  xyDataSeries.append(1, 10); // Appends X=1, Y=10
  xyDataSeries.append(2, 20); // Appends X=2, Y=20
  xyDataSeries.appendRange([3, 4, 5], [30, 40, 50]); // Appends X=3,4,5 and Y=30,40,50
  xyDataSeries.removeAt(0); // removes the 0th xy point
  xyDataSeries.removeRange(0, 2); // Removes 2 points from index 0 onwards
  xyDataSeries.insert(0, 100, 200); // Inserts X=100, Y=200 at index 0
  //xyDataSeries.insertRange(...)
  xyDataSeries.update(0, 22); // Updates the Y-value at index 0
  xyDataSeries.clear(); // Clears the dataseries. NOTE: Does not free memory
  xyDataSeries.delete(); // Deletes WebAssembly memory. The series is no longer usable.
  

If you still have trouble, i suggest sharing a complete project in Dropbox or Github that we can run. Our developers will be able to show you the best way to use SciChart.

Best regards,
Andrew

  • You must to post comments
Best Answer
0
0

I would suggest for new questions, ask a new forum question (don’t append more questions to this one)

The correct way to remove & delete a RenderableSeries is as follows:

for (let i=0; i<sciChartSurfaceRef.renderableSeries.items.length; i++) {
    if (sciChartSurfaceRef.renderableSeries.items[i].id == traceNum) { 
        var series = sciChartSurfaceRef.renderableSeries.get(i); // Gets the series from the collection
        sciChartSurfaceRef.renderableSeries.removeAt(i); // Removes the series from the chart
        series.delete(); // Will delete RenderableSeries **and** its DataSeries 
        break; 
    }
} 

I would also suggest looking at the TypeDoc for these functions because we’ve written extensive help files! For example:

SciChartSurface.renderableSeries returns ObservableArray<IRenderableSeries>

ObservableArray<T> has functions like add() get() removeAt() set() remove() insert() clear() and contains()

Modifying SciChartSurface.renderableSeries via these functions will cause the chart to redraw and update automatically.

Best regards,
Andrew

  • You must to post comments
1
0

Yes, of course SciChart can draw large datasets.

We have tested single series up to 100,000,000 (100 million) datapoints, and also thousands of series on a single chart. See our performance tests carried out here.

The problem you’re seeing looks like you might be running out of memory. This could be caused by your application or how you’re using SciChart.

Perhaps you can share with us a full code sample that reproduces this problem? Our team would be able to investigate.

Best regards,
Andrew

  • You must to post comments
1
0

Hi Andrew,

Please check the codes below. I hope that it’s enough for investigation.

Initializing the chart:

const sciChartSurfaceRef = useRef(null);
const wasmContextRef = useRef(null);

async function initSciChart() {   
    // LICENSING //
    SciChartSurface.setRuntimeLicenseKey("......");

// Create the SciChartSurface in the div 'scichart-root'
// The SciChartSurface, and webassembly context 'wasmContext' are paired. This wasmContext
// instance must be passed to other types that exist on the same surface.
const chartDefinition = {
  surface: { theme: { type: "Light", axisTitleColor: "#1d4e8f"  } },
  xAxes: [{
    type: EAxisType.NumericAxis,
    options: {
      axisTitle: "Frequency (GHz)",
      visibleRange: new NumberRange(6, 8),
    }
  }],
  yAxes: [{
    type: EAxisType.NumericAxis,
    options: {
      axisTitle: "Power (dBm)",
      axisAlignment: EAxisAlignment.Left,
      visibleRange: new NumberRange(-140, -40),
      zoomExtentsToInitialRange: true
    }
  }],
  series: [
        { 
            type: ESeriesType.LineSeries, 
            options: {
                stroke: "#FE9200",
                strokeThickness: 1,
            }, 
            xyData: { xDataId: "x", yDataId: "line0", dataIsSortedInX: true, dataEvenlySpacedInX: true, containsNaN: false } 
        },
        { 
            type: ESeriesType.LineSeries, 
            options: {
                stroke: "#FCDC00",
                strokeThickness: 1
            }, 
            xyData: { xDataId: "x", yDataId: "line1", dataIsSortedInX: true, dataEvenlySpacedInX: true, containsNaN: false } 
        },
        { 
            type: ESeriesType.LineSeries, 
            options: {
                stroke: "#7B64FF",
                strokeThickness: 1
            }, 
            xyData: { xDataId: "x", yDataId: "line2", dataIsSortedInX: true, dataEvenlySpacedInX: true, containsNaN: false } 
        },
        { 
            type: ESeriesType.LineSeries, 
            options: {
                stroke: "#68CCCA",
                strokeThickness: 1
            }, 
            xyData: { xDataId: "x", yDataId: "line3", dataIsSortedInX: true, dataEvenlySpacedInX: true, containsNaN: false } 
        },
        { 
            type: ESeriesType.LineSeries, 
            options: {
                stroke: "#B0BC00",
                strokeThickness: 1
            }, 
            xyData: { xDataId: "x", yDataId: "line4", dataIsSortedInX: true, dataEvenlySpacedInX: true, containsNaN: false } 
        },
        { 
            type: ESeriesType.LineSeries, 
            options: {
                stroke: "#653294",
                strokeThickness: 1
            }, 
            xyData: { xDataId: "x", yDataId: "line5", dataIsSortedInX: true, dataEvenlySpacedInX: true, containsNaN: false } 
        },
    ]
};
const { sciChartSurface, wasmContext } = await chartBuilder.build2DChart("scichart-root", chartDefinition);  

SciChartDefaults.enableResampling = true;
SciChartDefaults.asyncLabels = true;
SciChartDefaults.useSharedCache = true;

sciChartSurfaceRef.current = sciChartSurface;
wasmContextRef.current = wasmContext;
}

useEffect(() => {
    initSciChart();
}, []);

Update chart data:

const updateSpecDatasets = (newData, traceNumArr) => {  
    /*
    * newData - data array in size 131105. Sample values: [-116.86547088623047, -124.28397369384766, -122.37535858154297......]
    * traceNumArr - array contains trace number that need to be displayed. Sample values: [0, 1, 2, 3]
    *
    */
    if (!newData.length) { return; }

    let i, dataX;
    const arrLen = newData.length;
    const xInterval = 0.000015254948324;
    let pos = 6;

    dataX = [];
    for (i=0; i<arrLen; i++) {
        dataX.push(pos);
        pos += xInterval;
    }

    traceNumArr.forEach((tnum) => {
        if (sciChartSurfaceRef.current.renderableSeries.get(tnum)) {
            console.time("create new series with Flags");
            sciChartSurfaceRef.current.renderableSeries.get(tnum).dataSeries = new XyDataSeries(wasmContextRef.current, { xValues: dataX, yValues: newData });
            console.timeEnd("create new series with Flags");
        }
    });

    newData = [];
};
  • You must to post comments
0
0

Hi Andrew,

Thanks for pointing out the WebAssembly memory issue. It works very well now after modified the codes for updating chart data.

  • Andrew Burnett-Thompson
    Nice! I noticed that after you posted the second code sample. Sorry I did not notice before. All types which have .Delete() in SciChart must be deleted once you are done. These include: DataSeries, SciChartSurface and renderableSeries. If you call .Delete() once on the SciChartSurface it will delete all its child objects
  • Kelly Chan
    Got it, thanks!
  • You must to post comments
0
0

I just got another question about the deleting RenderableSeries. I tried to delete a lineSeries and then add later like that:

 //Remove a RenderableSeries, traceNum=0 
for (let i=0; i<sciChartSurfaceRef.renderableSeries.items.length; i++) {
    if (sciChartSurfaceRef.renderableSeries.items[i].id == traceNum) { 
        sciChartSurfaceRef.renderableSeries.items[i].delete(); 
        break; 
    }
} 


//Re-add aRenderableSeries: 
const xyDataSeries = new XyDataSeries(wasmContextRef); 
const lineSeries = new FastLineRenderableSeries(wasmContextRef, {
    type: ESeriesType.LineSeries, 
    id: 0, 
    stroke:"#FE9200", 
    strokeThickness: 1, 
    dataIsSortedInX: true, 
    dataEvenlySpacedInX: true,
    containsNaN: false, 
    dataSeries: xyDataSeries,
});
 sciChartSurfaceRef.renderableSeries.add(lineSeries);

When I try to re-add the trace, I found that there sciChartSurfaceRef.renderableSeries.items[0] is still there. I expected it’s removed when I call sciChartSurfaceRef.renderableSeries.items[i].delete();. Is it a correct way to remove series like this?

  • You must to post comments
Showing 6 results
Your Answer

Please first to submit.