4

I would like to automatically change the y-axis by using a dynamic plot. I changed the dynamic plot example in the examples and have appended lots of points. After a new point is appended, the plot should adjust its y-axis to account for the new maximum value. Is it possible for the plot to do this automatically?

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Gokhan Sahin
  • 165
  • 2
  • 15

1 Answers1

5

We can use the signal pointAdded of the series to update the range, for this we will create 2 variables that store the maximum and minimum, respectively:

connect(m_series, &QSplineSeries::pointAdded, [=](int index){
    qreal y = m_series->at(index).y();

    if(y< yMin || y > yMax){
        if(y < yMin)
            yMin = y;
        if(y> yMax)
            yMax = y;
        axisY()->setRange(yMin-20, yMax+20);
    }

});

Complete code:

chart.h

#ifndef CHART_H
#define CHART_H

#include <QtCharts/QChart>
#include <QTimer>

QT_CHARTS_BEGIN_NAMESPACE
class QSplineSeries;
class QValueAxis;
QT_CHARTS_END_NAMESPACE

QT_CHARTS_USE_NAMESPACE

//![1]
class Chart: public QChart
{
    Q_OBJECT
public:
    Chart(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0);
    virtual ~Chart();

public slots:
    void handleTimeout();

private:
    QTimer m_timer;
    QSplineSeries *m_series;
    QStringList m_titles;
    QValueAxis *m_axis;
    qreal m_step;
    qreal m_x;
    qreal m_y;
    //new variables
    qreal yMin;
    qreal yMax;
};
//![1]

chart.cpp

#include "chart.h"
#include <QtCharts/QAbstractAxis>
#include <QtCharts/QSplineSeries>
#include <QtCharts/QValueAxis>
#include <QTime>
#include <QDebug>

Chart::Chart(QGraphicsItem *parent, Qt::WindowFlags wFlags):
    QChart(QChart::ChartTypeCartesian, parent, wFlags),
    m_series(0),
    m_axis(new QValueAxis),
    m_step(0),
    m_x(5),
    m_y(1)
{
    qsrand((uint) QTime::currentTime().msec());

    connect(&m_timer, &QTimer::timeout, this, &Chart::handleTimeout);
    m_timer.setInterval(1000);

    m_series = new QSplineSeries(this);

    QPen green(Qt::red);
    green.setWidth(3);
    m_series->setPen(green);
    m_series->append(m_x, m_y);

    addSeries(m_series);
    createDefaultAxes();
    setAxisX(m_axis, m_series);
    m_axis->setTickCount(5);

    yMax = 10;
    yMin = -5;

    axisX()->setRange(0, 10);
    axisY()->setRange(yMin, yMax);

    connect(m_series, &QSplineSeries::pointAdded, [=](int index){
        qreal y = m_series->at(index).y();

        if(y< yMin || y > yMax){
            if(y < yMin)
                yMin = y;
            if(y> yMax)
                yMax = y;
            axisY()->setRange(yMin-20, yMax+20);
        }

    });

    m_timer.start();
}

Chart::~Chart()
{

}

void Chart::handleTimeout()
{
    qreal x = plotArea().width() / m_axis->tickCount();
    qreal y = (m_axis->max() - m_axis->min()) / m_axis->tickCount();
    m_x += y;
    //m_y = qrand() % 5 - 2.5;
    m_y = 50*(qrand() % 5 - 2.5);
    m_series->append(m_x, m_y);
    scroll(x, 0);
    if (m_x == 100)
        m_timer.stop();
}

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • I have tried to add on the mainwindow (GUI), but couldn't do, also it's not working signal/slot for the timer too. The connection is only running in main.cpp, why? Where do I mistake? void MainWindow::initChart() { Chart *chart = new Chart(); chart->setTitle("Dynamic spline chart"); chart->legend()->hide(); chart->setAnimationOptions(QChart::AllAnimations); QChartView chartView(chart); chartView.setRenderHint(QPainter::Antialiasing); QApplication::connect(chart->m_timer, &QTimer::timeout, chart, &Chart::handleTimeout); } – Gokhan Sahin Jul 06 '17 at 07:40
  • I did it :) Should I remove qlineseries because it always appends new point while running. – Gokhan Sahin Jul 06 '17 at 09:59
  • 2
    @eyllanesc Since you only track the min/max y value, what happens when it is no longer visible and removed from the series? – uniquenamehere Aug 12 '19 at 21:28
  • @iQt the lambda method is still running, if you want to optimize my code then add those requirements in the lambda to avoid executing that logic – eyllanesc Aug 12 '19 at 23:17