David
David

Reputation: 163

Android Studio - MPAndroidChart Add User Input to Line Graph

Hey guys it is my first time using MPandroidChart and I am currently experimenting with it to fully understand how to use it and its capabilities. Presently, I am trying to update my line graph using the data inputted by the user (through fragments). I've seen a few similar questions on stack overflow, however none of them have seemed to work for me.

Any help would be much appreciated. Thanks in advance.

Note: There is some repeated code, since I was experimenting and trying to figure out different approaches in search of a solution.

MainFragment that gets user input

public class Fragment1 extends Fragment {

EditText Input;
Button EnterVal;
public float userInput;

//Fragment1Listener activityCommander;

public interface Fragment1Listener{
    void sendInput(float value);
}

/*@Override
public void onAttach(Context context) {
    super.onAttach(context);
    try{
        activityCommander = (Fragment1Listener) getTargetFragment();
    }catch (ClassCastException e){
        throw new ClassCastException(context.toString() + "Must Implement FragmentListener");
    }
}*/

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment1, container, false);

    //@SuppressWarnings("all")

    Input = view.findViewById(R.id.Input);
    EnterVal = view.findViewById(R.id.button);


    EnterVal.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            String val = Input.getText().toString();

            if(val != null && val.length() > 0) {
                userInput = Float.valueOf(val);
                Input.setText("");
                /*if(activityCommander != null) {
                    activityCommander.sendInput(userInput);
                }*/
                Fragment1Listener listener = getListener();
                if(listener != null){
                    listener.sendInput(userInput);
                    Log.d("User Val", "Listener was successfull!");
                }
            }
        }
    });

    return view;
}

@Nullable
private Fragment1Listener getListener(){
    Fragment1Listener activityCommander;
    try{
        Fragment onInputSelected_Frag = getTargetFragment();
        if(onInputSelected_Frag != null){
            activityCommander = (Fragment1Listener) onInputSelected_Frag;
        }
        else{
            Activity onInputSelected_Act = getActivity();
            activityCommander = (Fragment1Listener) onInputSelected_Act;
        }
        return activityCommander;
    }catch(ClassCastException e){
        Log.e("Fragment Listener", "getListener: ClassCastException + " + e.getMessage());
    }
    return null;
}
}

MPandroidchart Fragment (line graph)

public class Fragment2 extends Fragment implements Fragment1.Fragment1Listener{

private LineChart lineChart;
//public Fragment1 fragment1;

private ArrayList<ILineDataSet> DataSets = new ArrayList<>();
private LineDataSet lineDataSet5;
private ArrayList<Entry> userData = new ArrayList<>();
private LineData data = new LineData(DataSets);

@Override
public void sendInput(float value) {

    data = lineChart.getData();
    ILineDataSet xSet = data.getDataSetByIndex(0);

    data.addEntry(new Entry(xSet.getEntryCount(), value),0);

    //lineDataSet5.notifyDataSetChanged();
    //lineDataSets.add(lineDataSet5);
    data.notifyDataChanged();
    lineChart.notifyDataSetChanged();
    lineChart.invalidate();
    lineChart.moveViewToX(data.getEntryCount());
}

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment2, container, false);

    lineChart = view.findViewById(R.id.LineChart);

    //Enable Touch Gestures
    lineChart.setTouchEnabled(true);

    //We want also enable scaling and dragging
    lineChart.setDragEnabled(true);
    lineChart.setScaleEnabled(true);

    //Enable pinch zoom to avoid scaling x and y axis separately
    lineChart.setPinchZoom(true);

    //Double tap zoom to chart
    lineChart.setDoubleTapToZoomEnabled(true);

    //Alternate Background Color
    lineChart.setBackgroundColor(Color.parseColor("#2b2b2b"));

    ArrayList<String> xAXES = new ArrayList<>();
    ArrayList<Entry> yAXESsin = new ArrayList<>();
    ArrayList<Entry> yAXEScos = new ArrayList<>();
    ArrayList<Entry> yAXEStan = new ArrayList<>();
    ArrayList<Entry> random = new ArrayList<>();

    double x = 0;
    int numDataPoints = 1000;
    for(int i =0; i<numDataPoints; i++){
        float sinFunction = Float.parseFloat(String.valueOf(Math.sin(x)));
        float cosFunction = Float.parseFloat(String.valueOf(Math.cos(x)));
        float tanFunction = Float.parseFloat(String.valueOf(Math.tan(x)));
        x += 0.1;
        yAXESsin.add(new Entry(i, sinFunction));
        yAXEScos.add(new Entry(i, cosFunction));
        yAXEStan.add(new Entry(i, tanFunction));
        xAXES.add(i, String.valueOf(x));

        final int randomVal = getRandomNumber(-10, 10);
        float randomData = (float) randomVal;
        random.add(new Entry(i, randomData));
    }

    String[] xaxes = new String[xAXES.size()];
    for(int i =0; i<xAXES.size(); i++){
        xaxes[i] = xAXES.get(i).toString();
    }

    //Add user Input
    //@SuppressWarnings("all")
    //userInput = fragment1.getUserInput();
    //userData.add(new Entry(userData.size()+1, userInput));

    ArrayList<ILineDataSet> lineDataSets = new ArrayList<>();
    ArrayList<ILineDataSet> dataSets = new ArrayList<>();

    //Data Set 1

    LineDataSet lineDataSet1 = new LineDataSet(yAXEScos, "Cos");
    lineDataSet1.setAxisDependency(YAxis.AxisDependency.LEFT);
    lineDataSet1.setDrawCircles(false);
    lineDataSet1.setColor(Color.parseColor("#B71C1C"));
    lineDataSet1.setLineWidth(3f);
    lineDataSet1.setHighlightEnabled(true);
    lineDataSet1.setDrawHighlightIndicators(true);
    lineDataSet1.setHighLightColor(Color.parseColor("#FF4081"));
    lineDataSet1.setValueTextSize(10f);
    lineDataSet1.setValueTextColor(Color.WHITE);
    lineDataSet1.setFillAlpha(110);

    //Data Set 2

    LineDataSet lineDataSet2 = new LineDataSet(yAXESsin, "Sin");
    lineDataSet2.setAxisDependency(YAxis.AxisDependency.LEFT);
    lineDataSet2.setDrawCircles(false);
    lineDataSet2.setColor(Color.parseColor("#33bbff"));
    lineDataSet2.setLineWidth(3f);
    lineDataSet2.setHighlightEnabled(true);
    lineDataSet2.setDrawHighlightIndicators(true);
    lineDataSet2.setHighLightColor(Color.parseColor("#FFD600"));
    lineDataSet2.setValueTextSize(10f);
    lineDataSet2.setValueTextColor(Color.WHITE);
    lineDataSet2.setFillAlpha(110);

    //Data Set 3

    LineDataSet lineDataSet3 = new LineDataSet(yAXEStan, "Tan");
    lineDataSet3.setAxisDependency(YAxis.AxisDependency.LEFT);
    lineDataSet3.setDrawCircles(false);
    lineDataSet3.setColor(Color.parseColor("#FFD600"));
    lineDataSet3.setLineWidth(3f);
    lineDataSet3.setHighlightEnabled(true);
    lineDataSet3.setDrawHighlightIndicators(true);
    lineDataSet2.setHighLightColor(Color.parseColor("#FFD600"));
    lineDataSet2.setValueTextSize(10f);
    lineDataSet2.setValueTextColor(Color.WHITE);
    lineDataSet2.setFillAlpha(110);

    //Data Set 4

    /*LineDataSet lineDataSet4 = new LineDataSet(random, "Random Numbers");
    lineDataSet4.setAxisDependency(YAxis.AxisDependency.LEFT);
    lineDataSet4.setDrawCircles(false);
    lineDataSet4.setColor(Color.parseColor("#00897B"));
    lineDataSet4.setLineWidth(3f);
    lineDataSet4.setHighlightEnabled(true);
    lineDataSet4.setDrawHighlightIndicators(true);
    lineDataSet4.setHighLightColor(Color.parseColor("#64FFDA"));
    lineDataSet4.setValueTextSize(10f);
    lineDataSet4.setValueTextColor(Color.WHITE);
    lineDataSet4.setFillAlpha(110);*/

    //Data set 5 - User Input
    lineDataSet5 = new LineDataSet(userData, "User Data");
    lineDataSet5.setAxisDependency(YAxis.AxisDependency.LEFT);
    lineDataSet5.setDrawCircles(false);
    lineDataSet5.setColor(Color.parseColor("#9C27B0"));
    lineDataSet5.setLineWidth(3f);
    lineDataSet5.setHighlightEnabled(true);
    lineDataSet5.setDrawHighlightIndicators(true);
    lineDataSet5.setHighLightColor(Color.parseColor("#E040FB"));
    lineDataSet5.setValueTextSize(10f);
    lineDataSet5.setValueTextColor(Color.WHITE);
    lineDataSet5.setFillAlpha(110);

    //Add Data sets
    lineDataSets.add(lineDataSet1);
    lineDataSets.add(lineDataSet2);
    lineDataSets.add(lineDataSet3);
    //lineDataSets.add(lineDataSet4);
    //lineDataSets.add(lineDataSet5);

    lineChart.setData(new LineData(lineDataSets));
    lineChart.setData(new LineData());
    lineChart.setVisibleXRangeMaximum(65f);
    lineChart.setHighlightPerTapEnabled(true);

    //Get legend object
    Legend legend = lineChart.getLegend();

    //Customize Legend
    legend.setForm(Legend.LegendForm.LINE);
    legend.setTextColor(Color.WHITE);

    //Set x axis
    XAxis xAxis = lineChart.getXAxis();
    xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
    xAxis.setTextColor(Color.WHITE);
    xAxis.setTextSize(10f);
    xAxis.setDrawGridLines(true);
    xAxis.setAvoidFirstLastClipping(true);

    //Set y axis
    YAxis yAxis = lineChart.getAxisLeft();
    yAxis.setTextColor(Color.WHITE);
    yAxis.setTextSize(10f);
    yAxis.setDrawGridLines(true);
    yAxis.setAxisMaximum(10f);
    yAxis.setAxisMinimum(-10f);

    //Disable Right y-axis values
    lineChart.getAxisRight().setEnabled(false);

    //Set Description
    lineChart.getDescription().setText("Sin and Cos Functions");
    lineChart.getDescription().setTextColor(Color.WHITE);

    //Update and refresh for User Input
    lineChart.notifyDataSetChanged(); //let the chart know it's data changed
    lineChart.invalidate(); //Refresh

    return view;
}

private int getRandomNumber(int min,int max) {
    return (new Random()).nextInt((max - min) + 1) + min;
}
}

MainActivity:

It manages for 2 tabs, one tab contains the EditText for user to input their value, and the other tab contains the line graph that I want to be updated.

public class MainActivity extends AppCompatActivity {

private SectionsPagerAdapter mSectionsPagerAdapter;

private ViewPager mViewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

    // Set up the ViewPager with the sections adapter.
    mViewPager = findViewById(R.id.container);
    //mViewPager.setAdapter(mSectionsPagerAdapter);
    setupViewPager(mViewPager);

    TabLayout tabLayout = findViewById(R.id.tabs);
    tabLayout.setupWithViewPager(mViewPager);

    mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
    tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });

}

private void setupViewPager(ViewPager viewPager){
    SectionsPagerAdapter adapter = new SectionsPagerAdapter(getSupportFragmentManager());
    adapter.addFragment(new Fragment1(), "Fragment 1");
    adapter.addFragment(new Fragment2(), "Fragment 2");
    viewPager.setAdapter(adapter);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}
}

Upvotes: 1

Views: 1518

Answers (1)

Tyler V
Tyler V

Reputation: 10920

You may be able to set the listener more directly. Try adding this method to Fragment1 (and removing getListener)

void setListener(Fragment1Listener listener) {
    activityCommander = listener;
}

then setting the listener in your Activity like this

private void setupViewPager(ViewPager viewPager){
    SectionsPagerAdapter adapter = new SectionsPagerAdapter(getSupportFragmentManager());
    Fragment1 f1 = new Fragment1();
    Fragment2 f2 = new Fragment2();
    f1.setListener(f2);
    adapter.addFragment(f1, "Fragment 1");
    adapter.addFragment(f2, "Fragment 2");
    viewPager.setAdapter(adapter);
}

There could be issues with this approach when the screen is rotated, but this should get you over this hurdle at least. If you want to continue using the getTargetFragment approach you'll need to call setTargetFragment somewhere too (see this question). Something like f1.setTargetFragment(f2); instead of f1.setListener(f2) in the code above.

I think you'll need to make some changes to the graph part once the listener is working to get it working still. For example, replace

lineChart.setData(new LineData(lineDataSets));
lineChart.setData(new LineData()); // this overrides the previous line with an empty data set

with

data.addDataSet([... the sets you want to add ...]);
lineChart.setData(data);

but this should get you started on the right path at least.

Upvotes: 2

Related Questions