I'm having an issue in my app where adding a large number of data points, clearing them, adding a smaller number of datapoints causes the LineChart
to not completely reach the end of the view.
I recreated this issue with a simple LineChart
.
In the linechart, I first add 365 data points by clicking the Add 365
button and it successfully loads all the points into the LineChart
view with a width of 300dp
.
Next, I click the Add 25
button to load the 25 data points into the LineChart
, but as you can see the line no longer reaches the end of the view for some reason.
I thought this might be because the chart is zoomed all the way out, so I added lineChart.fitScreen()
but it doesn't do anything.
So I'm no longer sure what the problem is. Does anyone know what I'm doing incorrectly?
public class MainActivity extends AppCompatActivity {
@BindView(R.id.linechart)
LineChart lineChart;
private final List<Entry> entries = new ArrayList<>();
private LineDataSet dataSet;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
dataSet = new LineDataSet(entries, null);
Drawable drawable = ContextCompat.getDrawable(this, R.drawable.gradient_purple);
dataSet.setFillDrawable(drawable);
dataSet.setLineWidth(1.5f);
dataSet.setDrawHorizontalHighlightIndicator(false);
dataSet.setHighLightColor(Color.WHITE);
dataSet.setHighlightLineWidth(1.5f);
dataSet.setColor(ContextCompat.getColor(this, R.color.teal_700));
dataSet.setDrawFilled(true);
dataSet.setDrawCircles(false);
dataSet.setDrawValues(false);
lineChart.setMinOffset(0f);
lineChart.getAxisLeft().setEnabled(false);
lineChart.getAxisRight().setEnabled(false);
lineChart.getXAxis().setEnabled(false);
lineChart.setNoDataText(null);
lineChart.setScaleEnabled(false);
lineChart.getDescription().setEnabled(false);
lineChart.getLegend().setEnabled(false);
}
@OnClick(R.id.btn_add_25)
void onAdd25() {
dataSet.clear();
for (int i = 0; i < 25; i++) {
Entry entry = new Entry(i, i);
dataSet.addEntry(entry);
}
LineData lineData = new LineData(dataSet);
lineChart.setData(lineData);
//lineChart.fitScreen(); Adding fitScreen doesn't do anything
lineChart.invalidate();
}
@OnClick(R.id.btn_add_365)
void onAdd365() {
dataSet.clear();
for (int i = 0; i < 365; i++) {
Entry entry = new Entry(i, i);
dataSet.addEntry(entry);
}
LineData lineData = new LineData(dataSet);
lineChart.setData(lineData);
//lineChart.fitScreen(); Adding fitScreen doesn't do anything
lineChart.invalidate();
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/purple_500"
android:elevation="4dp"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:text="Test App"
android:textColor="@color/white"
android:textSize="20sp" />
</androidx.appcompat.widget.Toolbar>
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/linechart"
android:layout_width="250dp"
android:layout_height="200dp"
android:clipToPadding="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
<Button
android:id="@+id/btn_add_25"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="300dp"
android:text="Add 25"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/btn_add_365"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="200dp"
android:text="Add 365"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Using version: implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
TL;DR - Call dataSet.calcMinMax()
after clearing and updating its data with a smaller dataset.
For whatever reason, the dataset is not clearing its min/max X & Y values when you call dataSet.clear();
, so when you had a dataset with X max of 364, adding a new dataset that only goes to 24 still keeps that old maximum, and the chart is drawn to that bound. The easy fix is to call calcMinMax()
on it manually yourself after filling it with smaller data set (or always as a best practice), like this:
dataSet.clear();
for (int i = 0; i < 25; i++) {
Entry entry = new Entry(i, i);
dataSet.addEntry(entry);
}
// if you print out dataSet.getXMax() here, it shows 364 if
// you plotted the 365 point data set already
dataSet.calcMinMax();
// dataSet.getXMax() here will now be correct
Another approach, which is more robust to the dataset saving state like this, would be to generate a new dataset for each call. You could define a helper function to apply the formatting that takes a list of entries, like this:
private LineDataSet createDataSet(List<Entry> entries) {
LineDataSet dataSet = new LineDataSet(entries, null);
Drawable drawable = ContextCompat.getDrawable(this, R.drawable.gradient_purple);
dataSet.setFillDrawable(drawable);
dataSet.setLineWidth(1.5f);
dataSet.setDrawHorizontalHighlightIndicator(false);
dataSet.setHighLightColor(Color.WHITE);
dataSet.setHighlightLineWidth(1.5f);
dataSet.setColor(ContextCompat.getColor(this, R.color.teal_700));
dataSet.setDrawFilled(true);
dataSet.setDrawCircles(false);
dataSet.setDrawValues(false);
return dataSet;
}
then remove the dataSet
and entries
class members and calls to them in onCreate
and instead do something like this on onAdd25
and onAdd365
void onAdd365() {
ArrayList<Entry> entries = new ArrayList<>();
for (int i = 0; i < 365; i++) {
Entry entry = new Entry(i, i);
entries.add(entry);
}
LineDataSet dataSet = createDataSet(entries);
LineData lineData = new LineData(dataSet);
lineChart.setData(lineData);
lineChart.invalidate();
}