gearquicker
gearquicker

Reputation: 581

MPAndroidChart: Creating a closed chart (circular line chart)

I need to draw a "closed chart" in my Android app, like this:

a line chart that forms a rough circle

The xIndex of the data first increases then decreases. Like in this example:

[3,3],[4,4],[5,5],[6,4],[7,3],[6,2],[5,1],[4,2],[3,3]

When I try drawing a LineСhart with this data in MPAndroidChart, it only renders the first half of data (prior to the fall of the xIndex). The other data is not shown.

How can I draw this data correctly with MPAndroidChart ?

Upvotes: 2

Views: 724

Answers (1)

David Rawson
David Rawson

Reputation: 21487

The sample app on the Google Play Store gives an example of every kind of chart available in the library. Likewise, the source code is available for you to inspect and see if it has the feature you want.

Additionally, the wiki specifically says that unordered line chart entries are not supported.

Please be aware that this library does not officially support drawing LineChart data from an Entry list not sorted by the x-position of the entries in ascending manner.

That being said, if you are willing to pre-process your data you should be able to achieve what you want. You would have to take your data and extract two distinct DataSets to which you would apply the same styling. I was able to achieve something like the effect you want using this technique:

a "closed chart" in blue

Here is the code:

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.Menu;
import android.view.WindowManager;
import android.widget.SeekBar;
import android.widget.TextView;

import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.Legend.LegendForm;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.xxmassdeveloper.mpchartexample.notimportant.DemoBase;

import java.util.ArrayList;
import java.util.Random;

public class LineChartActivity4 extends DemoBase {

    private LineChart mChart;
    private Random rand;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        rand = new Random();
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_linechart);

        mChart = (LineChart) findViewById(R.id.chart1);
        mChart.setDrawGridBackground(false);
        mChart.getDescription().setEnabled(false);
        mChart.setTouchEnabled(true);
        mChart.setScaleXEnabled(true);
        mChart.setScaleYEnabled(true);
        mChart.setPinchZoom(true);
        mChart.getLegend().setEnabled(false);
        YAxis leftAxis = mChart.getAxisLeft();
        leftAxis.removeAllLimitLines(); // reset all limit lines to avoid overlapping lines
        leftAxis.enableGridDashedLine(10f, 10f, 0f);
        leftAxis.setDrawZeroLine(false);
        leftAxis.setDrawLimitLinesBehindData(true);
        mChart.getAxisRight().setEnabled(true);
        mChart.setDragOffsetX(20);
        mChart.setData(generateClosedData(90, 180, 15));
        mChart.animateX(2500);
    }

    private LineData generateClosedData(float offset, float range, float delta) {
        ArrayList<Entry> topEntries = new ArrayList<>();
        ArrayList<Entry> bottomEntries = new ArrayList<>();

        for (int x = 0; x <= 180; x++) {
            float val1 = offset + generateValue(x, range, delta);
            float val2 = offset - generateValue(x, range, delta);
            topEntries.add(new Entry(x, val1));
            bottomEntries.add(new Entry(x, val2));
        }

        LineDataSet set1 = generateLineDataSet(topEntries);
        LineDataSet set2 = generateLineDataSet(bottomEntries);

        ArrayList<ILineDataSet> dataSets = new ArrayList<>();
        dataSets.add(set1);
        dataSets.add(set2);
        LineData data = new LineData(dataSets);
        return data;
    }

    private float generateValue(int x, float range, float delta) {
        float sine = (float) Math.sin(Math.toRadians(x));
        float scaledSine = sine * range;
        if (x == 0 || x == 180) {
            return scaledSine;
        }
        else {
            return scaledSine + rand.nextFloat() * delta;
        }
    }

    @NonNull
    private LineDataSet generateLineDataSet(ArrayList<Entry> topEntries) {
        LineDataSet set;
        set = new LineDataSet(topEntries, "");
        set.setColor(Color.BLUE);
        set.setDrawCircles(false);
        set.setLineWidth(4f);
        set.setValueTextSize(9f);
        set.setFormSize(15.f);
        return set;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.line, menu);
        return true;
    }
}

Upvotes: 1

Related Questions