Skip to content

Add the possibility to addEntries to a chart, without updating the whole dataSets - #752

Open
angelos3lex wants to merge 21 commits into
wuxudong:masterfrom
angelos3lex:master
Open

Add the possibility to addEntries to a chart, without updating the whole dataSets#752
angelos3lex wants to merge 21 commits into
wuxudong:masterfrom
angelos3lex:master

Conversation

@angelos3lex

@angelos3lex angelos3lex commented Sep 29, 2020

Copy link
Copy Markdown

@wuxudong
Imagine you have to refresh the chart in ~60 fps. This can be done by updating the datasets and re-render, but after the dataSet reaches some hundreds of values, you can notice the performance drop. When the values go on to thousands, the are constant freezes to the ui, as the rendering of such a big dataSet is too expensive. The JS thread freezes and there is nothing you can do.

By this PR, a new addEntries method is introduced, giving the possibility to append just the entries needed to the dataSet. So, one, can just add 1 entry every 17ms, the chart will update natively, thus resulting to a steady ~60fps, no matter of the size of the dataSet. Even if it contains thousands of values, the communication through js to native will contain only the new added entries, so the freeze and expensive re-render is eliminated.

I have created a new public repo here demonstrating the new way to add values in real time. (check App.js file) If you wish, change the logic to the previously suggested one, and you will definitely understand and feel the difference from the first second. As the time goes one, and the dataSet gets more and more data, the performance boost is unbelievable.

PR workable on android and ios.

Also, i noticed that current master is not buildable in android at least.
react-native-charts-wrapper/android/src/main/java/com/github/wuxudong/rncharts/charts/ChartBaseManager.java:333: error: cannot find symbol chart.setMarker(marker);
So, i didn't merge this with master yet, but there are no conflicts up to now, so you can safely merge.
Also, do you think that you'll manage to fix the build errors and release master as a new stable release sometime?

@wuxudong

wuxudong commented Oct 4, 2020

Copy link
Copy Markdown
Owner

@angelos3lex Could you please provide an example to show how to use this new feature?
and why this feature [LiveUpdateProvider] is only applied to LineChart.js

@angelos3lex

angelos3lex commented Oct 10, 2020

Copy link
Copy Markdown
Author

@wuxudong I updated to add this possibility on BubbleChart, LineChart, BarChart, ScatterChart, HorizontalBarChart and CandleStickChart. I can't add an example to the Examples, as i can't currently build the example proj using the master branch, because of below error:

A problem occurred evaluating project ':app'.
> Could not get unknown property 'FLIPPER_VERSION' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.

Also, i can't build the example proj using my repo, cause of another error during loading of the bundler and the react-native-screens, which is probably resolved in your current master. But the error above doesn't let me build that either :P

A live repo where you can check the way to append entries with this new way for the moment is here, by checking the App.js file

@angelos3lex angelos3lex changed the title Add the possibility to addEntries to a LineChart, without updating the whole DataSets Add the possibility to addEntries to a chart, without updating the whole dataSets Oct 10, 2020
@angelos3lex

Copy link
Copy Markdown
Author

Also added a replaceDataSets method, which is useful when one wants to update some dataset values/configuration, and don;t want to rerender. Imagine if you have 3 datasets, and want to completely replace one of them with different values/configuration. But the other 2 need to remain the same. You would need to re-render and all the dataSets values would pass from the bridge. If you wanted to do this in 60fps, that would be impossible, for the same reason as the initial comment.

@hemgui

hemgui commented Nov 19, 2021

Copy link
Copy Markdown

Thanks @angelos3lex for sharing.
I have exactly the same need for a Live Chart screen with incoming values every 20ms.
How reliable is this PR ? Do you use it in a production App ?
Do you plan to merge it one day @wuxudong ?

@angelos3lex

Copy link
Copy Markdown
Author

Hey @hemgui, On our side we are only using the fork repo in our production app, without any problems for more than 1 year.
A limitation you may find is that it doesn't support live updates in CombinedChart using this optimized way, only the old setState way is possible.
Also, on my side, I can't guarantee that I'll keep this up to date with this repo master, as the fork is only used for internal purposes and keeping it up to date, is not in our plans (except ofc if its needed for a bug fix or something we also need) But you can also fork and apply any updates if you need it.
If you need any help concerning the usage let me know, I'll be happy to help

@arsh09

arsh09 commented Dec 29, 2021

Copy link
Copy Markdown

Hello @angelos3lex , thank you for this amazing PR.

We tested it on a live data coming in from a bluetooth device at 50Hz, and it provides a great performance boost. We were wondering if there is a way to remove the data points without re-rendering the complete graph? For example, if someone wants to keep the last 1000 samples on graph from incoming data, is there a method to remove the previous data points without re-rendering?

Thank you.

@angelos3lex

angelos3lex commented Dec 30, 2021

Copy link
Copy Markdown
Author

Hey thx for feedback. You can try using the replaceDatasets function.You need to pass the index of the dataset that you want to replace and just give it as values the last 1000 values that you want.

A possible limitation with this will be if you want to keep a lot of values. I guess this may be a bit more problematic because the values are transformed to JSON and back to pass through the bridge to native, so again this needs some time, but with re-render that would also be worse.

Another way you can achieve this (depends on your use case) may be by keeping the addEntries method and changing the xAxis.minimum so that the displayed values are the last wanted values. To change the xAxis prop without re-rendering you need to change it using the setNativeProps method. ie:

this._lineChartRef.getNativeComponentRef().setNativeProps({ 
    xAxis: { axisMinimum: this._minX } 
});

@arsh09

arsh09 commented Dec 30, 2021

Copy link
Copy Markdown

I like the second approach you suggested but I am concerned about keeping the data in memory (even on the native side) as the BLE device I am using sends data at 50Hz (for 1 hour) and that's a lot of data.

While looking at your PR, I realised that a new method similar to addEntries can be added such as removeEntries where on the native side, this can be used.

@angelos3lex

angelos3lex commented Feb 4, 2026

Copy link
Copy Markdown
Author

For anyone interested, up to commit 37a124 of my repo, it's working for RN with old architecture.

For new architecture and latest RN, it is fully supported on commit 08b2cc using interop layer.

…mmands

Use a safe view lookup pattern in every command method:
- first try viewRegistry[reactTag]
- fallback to uiManager.view(forReactTag:)
ios: add UIManager view fallback for all RNBarLineChartBaseManager commands
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants