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

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

Open
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

angelos3lex
Copy link

@angelos3lex angelos3lex commented Sep 29, 2020

@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
Copy link
Owner

wuxudong commented Oct 4, 2020

@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
Copy link
Author

angelos3lex commented Oct 10, 2020

@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
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
Copy link

hemgui commented Nov 19, 2021

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
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
Copy link

arsh09 commented Dec 29, 2021

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
Copy link
Author

angelos3lex commented Dec 30, 2021

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
Copy link

arsh09 commented Dec 30, 2021

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.

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