MPAndroidChart определяет точный/фиксированный интервал между значениями по оси x (время)

Я использую в приложении библиотеку MPAndroidChart, и теперь у меня есть линейный график:

введите описание изображения здесь

По оси X у меня есть секунды, и я хочу иметь такой же интервал между значениями по оси X. Теперь у меня 19:03 и 19:20, но я хочу 19:05, 19:10, 19:15 (так что интервал 300 секунд)...

Как мне это сделать?

Теперь я использую этот функционал:

 lineChart.setScaleMinima(115f, 1f);

но это не очень хорошо. Также я хочу, чтобы он изменился с 5-минутного интервала на 1 час или 1 день.

Это возможно?


person Pepa Zapletal    schedule 05.06.2018    source источник
comment
Вы звоните в centerViewPort? прочтите выпуск 120 и выпуск 14   -  person RonTLV    schedule 19.06.2018
comment
@RonTLV Нет, я не звоню в centerViewPort.   -  person Pepa Zapletal    schedule 19.06.2018
comment
Пробовали ли вы вычислить нужный интервал и установить его с помощью setAxisMinimum, setAxisMaximum и setLabelCount для достижения точного желаемого интервала (github.com/PhilJay/MPAndroidChart/wiki/The-Axis)?   -  person Tyler V    schedule 24.06.2018
comment
@TylerV Я не уверен, что именно ты думаешь. Как мне его использовать. Можешь написать больше информации? Может быть, какой-то пример?   -  person Pepa Zapletal    schedule 25.06.2018
comment
@TylerV, пожалуйста, предоставьте рабочий образец, если можете. Это то, что мне интересно, как это делается с MPAndroidChart. Мне нужны графики в реальном времени, а пример в примере приложения не очень хорош.   -  person Thracian    schedule 25.06.2018
comment
Также было бы здорово, если бы кто-нибудь мог предоставить образец, который выглядит точно так же, как изображение оператора.   -  person Thracian    schedule 25.06.2018
comment
@PepaZapletal, вы пытались установить степень детализации по оси X?   -  person Shrikant    schedule 26.06.2018


Ответы (1)


tl;dr Установите минимальные и максимальные значения по оси X, кратные нужному интервалу (например, кратные 5), и установите степень детализации оси на соответствующее кратное этому же интервалу (например, 5).

Полный пример Вот пример тестовой программы, показывающий, как установить границы осей и степень детализации, чтобы маркеры были кратны вашему выбору. Опция детализации устанавливает минимальное разрешение для оси, а установка значений xMin и xMax, кратных этому, означает, что расстояние между осями будет кратно выбранному вами. Обратите внимание, что если, например, вы выберете 5-минутный интервал, вы можете получить деления оси с интервалом в 10 минут (или 15 или 20), чтобы сохранить соответствующее количество осевых линий.

РЕДАКТИРОВАТЬ: OP спросил о графике в реальном времени, поэтому я обновил пример, чтобы построить синусоидальную волну в реальном времени.

package com.project.testchart;

import android.graphics.Color;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Description;
import com.github.mikephil.charting.components.Legend;
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 java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private final Handler handler = new Handler();
    private ArrayList<Entry> data = new ArrayList<>();

    @Override
    protected void onPause() {
        super.onPause();
        handler.removeCallbacksAndMessages(null);
    }

    @Override
    protected void onResume() {
        super.onResume();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                addPointToChart();
                drawChart();
                handler.postDelayed(this, 250);
            }
        }, 250);
    }

    private void addPointToChart() {

        while( data.size() > 100 ) {
            data.remove(0);
        }

        lastX += 1f;
        float y = (float)Math.sin(lastX/5f);
        data.add(new Entry(lastX,y));
    }

    private void drawChart() {

        float textSize = 20f;

        LineDataSet line = new LineDataSet(data, "Sin");
        line.setLineWidth(5);
        line.setColor(Color.BLACK);
        line.setDrawValues(false);
        line.setDrawCircles(false);
        line.setHighLightColor(Color.TRANSPARENT);

        LineData lines = new LineData();
        lines.addDataSet(line);

        LineChart chart = findViewById(R.id.test_chart);
        chart.setData(lines);

        Description desc = new Description();
        desc.setText("");
        chart.setDescription(desc);
        chart.setDrawBorders(true);

        YAxis yAxisR = chart.getAxisRight();
        yAxisR.setDrawGridLines(false);
        yAxisR.setEnabled(false);

        YAxis yAxisL = chart.getAxisLeft();
        yAxisL.setDrawGridLines(true);
        yAxisL.setDrawTopYLabelEntry(true);
        yAxisL.setTextSize(textSize);

        XAxis xAxis = chart.getXAxis();
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.setTextSize(textSize);

        float xMin = (float)Math.floor((line.getXMin()-xInterval)/xInterval)*xInterval;
        float xMax = (float)Math.ceil((line.getXMax()+xInterval)/xInterval)*xInterval;
        float xSpan = xMax - xMin;
        float xi = xSpan / 6; // approximately 6 labels
        float xGran = Math.max(xInterval,(float)Math.round(xi/xInterval)*xInterval);

        xAxis.setGranularity(xGran);
        xAxis.setAxisMinimum(xMin);
        xAxis.setAxisMaximum(xMax);

        Legend l = chart.getLegend();
        l.setOrientation(Legend.LegendOrientation.HORIZONTAL);
        l.setDrawInside(false);
        l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER);
        l.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP);
        l.setTextSize(textSize);

        chart.setExtraBottomOffset(10f);
        chart.setExtraRightOffset(20f);

        chart.invalidate();
    }

    private float xInterval = 5f;
    private float lastX = 0f;

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

        float xStart = 3f;
        float xEnd = 7f;
        for(int i = 0; i < 4; ++i) {
            float x = xStart + (i/3f)*(xEnd-xStart);
            float y = (float)Math.sin(x/5f);
            data.add(new Entry(x,y));
        }
        lastX = xEnd;

        drawChart();
    }
}

И XML-файл

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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=".MainActivity">

    <com.github.mikephil.charting.charts.LineChart
        android:id="@+id/test_chart"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="32dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

</android.support.constraint.ConstraintLayout>

Несколько скриншотов для разных диапазонов данных

Пример скриншотов

person Tyler V    schedule 26.06.2018
comment
Я протестировал использование setGranularity в своем приложении, но у меня это не работает. Я установил xInterval = 300 (5 минут в секундах) и xMin у меня -300; xMax = 2469600 (секунды в будущем), и мне нужен 5-минутный интервал по оси X между этими точками. Если я использую ваш код, у меня сразу появляется весь график на экране с неправильным интервалом. Пожалуйста, посмотрите на этот снимок экрана: ibb.co/fptWc8 (обратите внимание, я отключил масштабирование, я хочу только проводить пальцем влево/вправо). на графике) - person Pepa Zapletal; 27.06.2018
comment
Поскольку у вас есть эти гистограммы на графике, вам нужно получить xMin и xMax только из вашего набора данных (LineDataSet для белой линии), а не из LineData. Кроме того, ваши необработанные данные x в минутах или в каком-то меньшем приращении данных? - person Tyler V; 27.06.2018
comment
Мои данные строки x в секундах. Также обратите внимание, что интервал между значениями x не обязательно должен быть всегда одинаковым, и некоторые значения x могут отсутствовать. Пример значений x: 15, 30, 42, 60, 85..и интервал по оси x всегда должен быть 5 минут (или 10 минут...) - person Pepa Zapletal; 27.06.2018
comment
Я обновил ответ, чтобы динамически установить степень детализации на основе диапазона видимых данных и приблизительного количества желаемых меток. Как я уже говорил, вам нужно получить xMin и xMax из LineDataSet для вашей белой линии и установить xInterval в секундах (например, 300 для 5-минутных интервалов). Если вы обнаружите, что ваши диапазоны таковы, что вы все еще получаете несколько меток, вы можете попробовать изменить желаемое количество меток (здесь 6). - person Tyler V; 28.06.2018
comment
Это все еще не работает нормально для меня. Но setScaleMinima() выглядит лучше, но я не знаю, как рассчитать правильный коэффициент scaleX. У вас есть какое-то представление об этом? - person Pepa Zapletal; 28.06.2018
comment
Что он делает? Что именно вы пробовали? Вы должны будете иметь возможность определить, какой диапазон данных вы хотите показать, независимо от того, какой метод вы используете. - person Tyler V; 29.06.2018
comment
Это ничего не делает. Я попробовал код из вашего примера, и график по-прежнему отображается сразу (без увеличения). Как здесь: ibb.co/fptWc8 и это неправильно. Да, мне нужно показать некоторый диапазон данных (увеличение). Как я должен это делать? Если я использую lineChart.setScaleMinima(1500, 1f);, то он показывает правильный интервал (5 минут). Но как рассчитать интервал в 1 час и 1 день? - person Pepa Zapletal; 03.07.2018
comment
Вы должны получить правильные значения для xMin и xMax, чего вы явно еще не делаете. Без публикации вашего кода я ничем не могу вам помочь. - person Tyler V; 03.07.2018
comment
Знаете ли вы заранее, каков диапазон данных x для белой линии, которую вы хотите показать? Если вам нужно вызвать getXMin для этого диапазона данных и по-прежнему получать 0, это означает, что в этом наборе данных есть какое-то значение, равное 0, или вы вызываете его для неправильного набора данных. - person Tyler V; 03.07.2018