MPAndroidChart x轴日期/时间标签间隔不规则

时间:2017-05-14 20:44:41

标签: android graph mpandroidchart

我有点难过。我查看了MPAndroidChart的文档以及这里提出的一系列问题,但我无法弄清楚是什么导致了它。

基本上,除非我有12个左右的标签,或者我只强制标签计数,否则我的图表中没有星期一。标签在周日晚上和周二早上一直放置,这导致星期一不被绘制。理想情况下,在某个缩放级别,我应该看到几个月,然后是几天,然后是几个小时,但标签必须在逻辑位置(月的第一天,午夜,小时的开始等等)

我喜欢做的是能够强制xLabel的特定间隔。例如:在某个缩放级别有24小时,1小时或15分钟的间隔,但都是从午夜开始,所以不会有任何奇怪的时间标签。到目前为止,我还没有找到一个确认的解决方案...至少没有真实的,不规则的Epoch时间戳。提出了这个非常相似的问题,但它并没有引导任何地方:MPAndroidChart x-axis date/time label formatting

18362047_10155310951108420_632358_o

(没有星期一,除非你放大每小时视图,如果我强制标签格式显示天数,它们会变得可见)

我正在绘制各种数据点,但它们的x值是所有unix时间戳。

我的代码:

在我的onCreate中:

//        creates line graphs for al DPs
        for (int i = 0; i < activeDataPointIDs.size(); i++) {
//            gets id and dataPointLogic
            int id = DataPointsManager.activeDataPointIDs.get(i);
            DataPointLogic logic = DataPointsManager.getDataPointLogic(id);

//          creates the chart
            LineChart lineChart;
            lineChart = createLineGraph(logic, UnitConverter.dpToPixel(300, this));

    //            creates a label
            TextView textView = new TextView(this);
            textView.setText(DataPointsManager.dataPointNames[id]);


    //            adds the chart and label to the containing view
            mainContainer.addView(textView);
            mainContainer.addView(lineChart);

    //            adds the chart to a list accessible within the activity class
            lineChartList.add(lineChart);

        }


        calculateGraphRange();

calculateGraphRange():

  //    calculates the graph range based on the time interval selected
        void calculateGraphRange() {

        int days = CompassApp.daysToShowStats;


    //        figuring out stupid timezone offsets
        long baseOffset = TimeZone.getDefault().getRawOffset();
        long dstOffset = TimeZone.getDefault().getDSTSavings();
        long timezoneOffset = baseOffset + dstOffset;

    //        default values are set for 1 week, TODO: deal with timezones
        long graphMax = System.currentTimeMillis();
        long graphMaxExtra = graphMax % TimeUtilities.UNIX_DAY;
        graphMax = graphMax - graphMaxExtra + TimeUtilities.UNIX_DAY - timezoneOffset;
        long graphMin = graphMax - (TimeUtilities.UNIX_DAY * days);
    //

    //        prevents invalid graphs from being drawn //TODO: fix labels when range is 0 or null
        if (days == 0) {
            graphMax = 0;
            graphMin = 0;
        }

    //        applies to all charts
        for (int i = 0; i < lineChartList.size(); i++) {

            LineChart chart = lineChartList.get(i);

            chart.getXAxis().setAxisMaximum(graphMax);
            chart.getXAxis().setAxisMinimum(graphMin);


            chart.notifyDataSetChanged();
            chart.invalidate();

        }


    }

日期格式化程序中没有任何时髦。大多数都被注释掉以便于测试

 IAxisValueFormatter createDateFormatter() {
        IAxisValueFormatter formatter = new IAxisValueFormatter() {


            @Override
            public String getFormattedValue(float value, AxisBase axis) {
                Date date = new Date((long) value);

                SimpleDateFormat fmt;


//                switch (labelModeSelected) {
//                    case HOURS_FORMAT:
//                        fmt = new SimpleDateFormat("h:mm a");
//                        break;
//
//                    case DAYS_FORMAT:
//                        fmt = new SimpleDateFormat("E d");
//                        break;
//
//                    case WEEKS_FORMAT:
//                        fmt = new SimpleDateFormat("d MMM");
//                        break;
//
//                    case MONTHS_FORMAT:
//                        fmt = new SimpleDateFormat("MMM yyyy");
//                        break;
//
//                    case YEARS_FORMAT:
//                        fmt = new SimpleDateFormat("yyyy");
//
//                        break;
//
//                    default:
//                        fmt = new SimpleDateFormat("E d MMM");
//                        break;
//                }


                fmt = new SimpleDateFormat("MMM d H:mm zz"); //TODO remove after tests and add switch
                fmt.setTimeZone(TimeZone.getDefault()); // sets time zone... I think I did this properly...


                String s = fmt.format(date);


                return s;
            }

            // we don't draw numbers, so no decimal digits needed
            public int getDecimalDigits() {
                return 0;
            }


        };

        return formatter;
    }

创建线图的方法

    LineChart createLineGraph(DataPointLogic dataPointLogic, int height) {


        final LineChart lineChart = new LineChart(this);

        lineChart.setMinimumHeight(height);


        List<Entry> entries = new ArrayList<Entry>();

        List<Number> xList = new ArrayList<>();
        List<Number> yList = new ArrayList<>();

        xList = dataPointLogic.getXVals(); //TODO: does this just not work with the class inheritance
        yList = dataPointLogic.getYVals(); //TODO: does this just not work with the class inheritance


        for (int i = 0; i < xList.size(); i++) {

            long x = xList.get(i).longValue();
            float y = yList.get(i).floatValue();

            entries.add(new Entry(x, y));
        }

//
        final LineDataSet dataSet = new LineDataSet(entries, "Time series");
//        graph smoothing params
        dataSet.setCubicIntensity(0.5f);
        dataSet.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);

//        graph fill params
        dataSet.setDrawFilled(true);
//        dataSet.setFillDrawable(ContextCompat.getDrawable(this, R.drawable.doge));
        dataSet.setFillColor(primaryColor);

//        line params
        dataSet.setColor(primaryColor);
        dataSet.setLineWidth(1f);

//        circle params
        dataSet.setCircleRadius(2.5f);
        dataSet.setCircleColor(primaryColor);
        dataSet.setDrawCircleHole(false);


        LineData lineData = new LineData(dataSet);
        lineData.setDrawValues(false);


        lineChart.setData(lineData);
//
//        applies the timestamp formatting
        XAxis xAxis = lineChart.getXAxis();
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.setValueFormatter(createDateFormatter());
        xAxis.setDrawLabels(true);
        xAxis.setCenterAxisLabels(true);
        xAxis.setLabelRotationAngle(90f); // rotates label so we can see it all TODO remove after tests


        YAxis yAxisRight = lineChart.getAxisRight();
        yAxisRight.setDrawLabels(false);
        yAxisRight.setDrawGridLines(false);

        YAxis yAxisLeft = lineChart.getAxisLeft();
        yAxisLeft.setDrawGridLines(false);
        yAxisLeft.setSpaceBottom(0.0f);

//        removes description and legend
        lineChart.getLegend().setEnabled(false);
        lineChart.getDescription().setEnabled(false);

//        sets the maximum zoom... must be provided unix time values
        lineChart.setVisibleXRangeMinimum(TimeUtilities.UNIX_HOUR);

        lineChart.setOnChartGestureListener(new OnChartGestureListener() {
            @Override
            public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {

            }

            @Override
            public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {

            }

            @Override
            public void onChartLongPressed(MotionEvent me) {

            }

            @Override
            public void onChartDoubleTapped(MotionEvent me) {

            }

            @Override
            public void onChartSingleTapped(MotionEvent me) {

            }

            @Override
            public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {

            }

            @Override
            public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
                scaleChartLabels(lineChart);
            }

            @Override
            public void onChartTranslate(MotionEvent me, float dX, float dY) {

            }
        });

//        applies the scale
        scaleChartLabels(lineChart);


        lineChart.invalidate(); // refreshes data

        return lineChart;
    }

方法更改标签的显示方式,具体取决于图表的比例

  //    changes the scale of the chart labels depending on what is selected
    void scaleChartLabels(LineChart chart) {
        float max = chart.getHighestVisibleX();
        float min = chart.getLowestVisibleX();
        float totalXVisible = max - min;


        float granularity = TimeUtilities.UNIX_DAY;

        int labelCount = 0;

        //        conditional switch to determine display params of graphs
        if (totalXVisible < TimeUtilities.UNIX_DAY) {
            labelCount = 8;
            granularity = TimeUtilities.UNIX_HOUR;
            labelModeSelected = HOURS_FORMAT;
            // Day view
        } else if (totalXVisible < TimeUtilities.UNIX_DAY * 2) {
            labelCount = 2;
            granularity = TimeUtilities.UNIX_DAY;
            labelModeSelected = DAYS_FORMAT;
            // Week view
        } else if (totalXVisible < TimeUtilities.UNIX_DAY * 3) {
            labelCount = 3;
            granularity = TimeUtilities.UNIX_DAY;
            labelModeSelected = DAYS_FORMAT;
            // Week view
        } else if (totalXVisible < TimeUtilities.UNIX_DAY * 4) {
            labelCount = 4;
            granularity = TimeUtilities.UNIX_DAY;
            labelModeSelected = DAYS_FORMAT;
            // Week view
        } else if (totalXVisible < TimeUtilities.UNIX_DAY * 5) {
            labelCount = 5;
            granularity = TimeUtilities.UNIX_DAY;
            labelModeSelected = DAYS_FORMAT;
            // Week view
        } else if (totalXVisible < TimeUtilities.UNIX_DAY * 6) {
            labelCount = 6;
            granularity = TimeUtilities.UNIX_DAY;
            labelModeSelected = DAYS_FORMAT;
            // Week view
        } else if (totalXVisible < TimeUtilities.UNIX_WEEK) {
            labelCount = 7;
            granularity = TimeUtilities.UNIX_DAY;
            labelModeSelected = DAYS_FORMAT;
            // Week view
        } else if (totalXVisible < (TimeUtilities.UNIX_WEEK * 2)) {
            labelCount = 7;
            granularity = TimeUtilities.UNIX_DAY;
            labelModeSelected = DAYS_FORMAT;
            // Week view
        } else if (totalXVisible < TimeUtilities.UNIX_MONTH) {
            labelCount = 7;
            granularity = TimeUtilities.UNIX_DAY;
            labelModeSelected = WEEKS_FORMAT;
            //Month view
        } else if (totalXVisible < TimeUtilities.UNIX_MONTH * 3) {
            labelCount = 3;
            granularity = TimeUtilities.UNIX_MONTH;
            labelModeSelected = MONTHS_FORMAT;

            // 90 day view
        } else if (totalXVisible < TimeUtilities.UNIX_YEAR) {
            labelCount = 6;
            granularity = TimeUtilities.UNIX_MONTH;
            labelModeSelected = MONTHS_FORMAT;

            // year view
        } else if (totalXVisible > TimeUtilities.UNIX_YEAR) {
            Log.w(TAG, "case not implemented yet");
        }

        chart.getXAxis().setGranularityEnabled(true);
        chart.getXAxis().setGranularity(granularity);


        chart.getXAxis().setLabelCount(labelCount);
    }

2 个答案:

答案 0 :(得分:2)

事实证明,由于Entries使用了浮点数,我的时间戳上的精度正在下降......足以弄乱x轴上标签之间的间隔。

我把它们全部分成60 000作为一个快速测试,以毫秒为单位将我的时间戳以毫秒计入时间戳,这似乎就是诀窍。

答案 1 :(得分:0)

我遇到了同样的问题,我通过

解决了

1。设置

  

xAxis.setAxisMinimum(minimumPoint)

  

xAxis.setAxisMaximum(maximumPoint)

分别与起点和终点相对应。

  1. 然后使用此重载方法`
  

xAxis.setLabelCount(length,true)

`,其中length是标签数组的大小。