Passing current time in milliseconds to MPChart breaks it

橙三吉。 提交于 2019-12-11 17:06:49

问题


I have tried figuring this out, but it doesn't add up. The data doesn't appear as it should.

First I generate dummy data. This is done async because I need time between the calls to System.currentTimeMillis to get some spacing between them. (Look aside the crappy code here, this is just debug data that will not be in the release. Using Thread.sleep on the main thread is a bad idea considering ANR's)

public class AsyncGeneration extends AsyncTask<String, String, String>{
    public AsyncGeneration() {
        super();
    }
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
    }
    @Override
    protected void onProgressUpdate(String... values) {
        super.onProgressUpdate(values);
    }
    @Override
    protected void onCancelled(String s) {
        super.onCancelled(s);
    }
    @Override
    protected void onCancelled() {
        super.onCancelled();
    }
    @Override
    protected String doInBackground(String... strings) {
        while(root == null) {
            try {
                Thread.sleep(200);
            }catch(InterruptedException e){}
        }
        List<Entry> rdata = new ArrayList<>();
        for(int i = 1; i < 30; i++){
            try{
                Thread.sleep(200);
            }catch(Exception e){
                //IGNORE
            }

            float time = System.currentTimeMillis();
            Log.e("GChart", "Timex: " + time);
            Session s = new Session(r.nextInt(5000), time);//Replace time with the index in the for-loop and it works for some reason
            rdata.add(new Entry(s.getXValue(), s.getYValue()));
            Log.e("GChart", "Timey: " + s.getXValue());
        }

        final List<Entry> entries = rdata;
        OverviewFragment.this.getActivity().runOnUiThread(() ->{

            LineDataSet data = new LineDataSet(entries, "Distance");
            data.setCircleColor(Color.parseColor("#FF0000"));
            LineData lineData = new LineData(data);
            tab1chart.setData(lineData);

            tab1chart.invalidate(); // refresh

            tab1chart.getXAxis().setValueFormatter(new DateFormatter());
            tab1chart.getXAxis().setPosition(XAxis.XAxisPosition.BOTTOM);
            tab1chart.getXAxis().setTextSize(10f);
            tab1chart.getXAxis().setTextColor(Color.RED);
            tab1chart.getXAxis().setDrawAxisLine(true);
            tab1chart.getXAxis().setDrawGridLines(true);
            tab1chart.getAxisLeft().setValueFormatter(new DistanceValueFormatter());
            tab1chart.getAxisLeft().setDrawGridLines(true);
            Log.v("Chart", "Chart data loaded and invalidated");//This prints

        });
        return null;
    }
}

So far everything looks fine. The data gets put into the chart, no exceptions, no crashes.

When the chart renders, a single data point shows up at the far-left of the chart. I generate 30 data points, one shows up.

That's issue #1: Only one data point shows up.

Issue #2 is slightly harder. The entire X axis at the bottom disappears. X axis is gone and when zooming, the Y axis, and its text also disappears. This is fairly hard to explain, so here is a screenshot:

It is worth mentioning the fact that if I pass i in the for-loop as the time, it shows up just as expected: all the axises are in place, zoom doesn't break anything.

(Float values can take the same values as Longs except they have decimals in addition.)

And in addition, I format the data:

public class DateFormatter implements IAxisValueFormatter {
    SimpleDateFormat formatter;

    public DateFormatter(){
        formatter = new SimpleDateFormat("dd/MM/yy, HH:mm");
    }

    @Override
    public String getFormattedValue(float value, AxisBase axis) {
        //This method is never called. Nothing is returned
        if(axis instanceof XAxis) {
            String formatted = formatter.format(new Date((long) value));
            Log.d("Formatter", "Formatted \"" + value + "\" to \"" + formatted + "\".");
            return formatted;
        }
        return "Not supported";
    }
}

Removing the formatter doesn't change anything, the axis is still gone. Zoom still breaks the Y axis.

So my question is: How do I fix this? I don't get why the chart doesn't work when I pass the current time in milliseconds (and I checked the values with debug output, floats can handle it). I got some debug output earlier that eventually stopped coming at all that showed the value passed to the formatter was values < 2000. I can't reproduce this any more though

The chart itself doesn't appear to be broken but from touch events it looks like every single point is pushed into the same X coordinate but only one point renders. When I touch the chart, the orange-ish lines show up indicating the position of a data point. It pops up on points that aren't visible.

When I pass the for-loop index as the X value, it works as expected, the formatter works fine (looking aside the fact that it shows the date as in 1970, but it is counted as 1 millisecond into the epoch, so that is to expect)

I looked at this as well on formatting the date. When I then try passing the milliseconds since the epoch, the chart stops working.

I'm using MPChart v 3.0.2, compiling against Android 26, using Java 8, and running Android Studio 3.0 beta 2

As for the layout, it is just a LinearLayout with a LineChart in it.


This should work, but it breaks when I pass it the current time in milliseconds for some reason. Passing any other data (as long as the numbers aren't that big) works fine.

The two images are not how the chart is supposed to look. The X axis is supposed to be visible, but for some reason it isn't along with a large amount of the data.


回答1:


This is known issue of Android MPChart (have a read this thread). Time series chart supported in MPChart - You can set time (in millis) as X values for Hourly Charts.

But too many consecutive data (points) won't correctly plot in Line Charts. Because Entry object will accept only float values due to some performance constraints.

So, keep the first value as the reference and subtract each up coming value from reference value & divide by some constants (say 1000) .So , you X value set will be like 10,20,30....& so on.

Do the reverse logic in your Axis Value formatter to render the X Axis Label properly (see the code snippet).

lineChart.getXAxis().setValueFormatter(new IAxisValueFormatter() {
            @Override
            public String getFormattedValue(float value, AxisBase axis) {

                SimpleDateFormat format2 = new SimpleDateFormat("HH:mm:ss");
                return format2.format(new Date(firstTimeStamp + ((long) value) * 1000L));

            }

        });


来源:https://stackoverflow.com/questions/46214094/passing-current-time-in-milliseconds-to-mpchart-breaks-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!