Can someone provide a working example of VXYModelMapper with lineseries chart ?



  • I want to implement something like this .With a model from cpp and combined with line charts but I am not able to understand yColumn and xColumn as in what data shall I provide it and I would like to Append the data to the lineseries every time it is updated.

    qml:
    
    
    Rectangle {
        implicitWidth: implicitWidth + 2*anchors.margins
        implicitHeight: implicitHeight + 2*anchors.margins
        clip: true
        color: "#ddd"
        Item {
        id: valueDisp
        implicitWidth: 640
        implicitHeight: 640
    
        ChartView
        {
            id: chartView
            title: " Scope "
            anchors.fill: parent
            legend.visible: false
            antialiasing: true
            backgroundColor: "white"
            plotAreaColor: "white"
            titleColor: "white"
    
            ValueAxis {
                id: axisX
                titleText:componentData.readXAxisName
                min: componentData.changeXMin
                max: componentData.changeXMax
                tickCount: 1
            }
    
            ValueAxis {
                id: axisY
                titleText:componentData.readYAxisName
                min: componentData.changeYMin
                max: componentData.changeYMax
                tickCount: 1
            }
    
            LineSeries {
    
                id: lineSeries
                name: "Data Output"
                axisX: axisX
                axisY: axisY
                useOpenGL: true
                VXYModelMapper{
                model:componentData.dataRead
                }
            }
        }
    

    cpp:

    
    //this is a snippet of the code I am using :
    // in class ScopeData I a updating setXdata and setYdata and whenever I update them I assert valueAdded signal as well 
    Q_PROPERTY(QQmlListProperty<ChartData> dataRead READ dataRead NOTIFY valueAdded)
    
    QQmlListProperty<ChartData> ScopeData::dataRead()
    {
    	return QQmlListProperty<xpcv::ChartData> (this,m_chartData);
    }
    
    // these are the functions that I am using to update the data in the chart
    ChartData::ChartData(QObject *parent)
    	: QObject(parent),
    		m_xValue(0), 
    		m_yValue(0)
    	{}
    	void ChartData::setXdata(int data)
    	{
    		m_xValue=data;
    	}
    
    	void ChartData::setYdata(double data)
    	{
    		m_yValue=data;
    	}
    

    but I get the following error:
    unable to assign qmlListProperty<ChartData> to QAbstractItemModel
    PS- I cannot share the entire code because of privacy of project details
    Thank You,
    Saransh Vora



  • This subject is rather old but I also have not found any example and I took time to make it work.
    Below my proposal
    Click on the chart to randomly append data

    main.cpp

    #include <QQmlEngine>
    #include <QApplication>
    #include <QQmlApplicationEngine>
    #include "chartmodel.h"
    
    int main(int argc, char *argv[])
    {
    #if defined(Q_OS_WIN)
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    #endif
    
        QApplication app(argc, argv); //Use QApplication for QChart, QGuiApplication causes a bug
    
        qmlRegisterType<ChartModel> ("MainLib", 1, 0, "ChartModel");
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        if (engine.rootObjects().isEmpty())
            return -1;
    
        return app.exec();
    }
    

    chartmodel.h

    #ifndef CHARTMODEL_H
    #define CHARTMODEL_H
    
    #include <QVector>
    #include <QAbstractTableModel>
    //#include <QDebug>
    
    class ChartModel : public QAbstractTableModel
    {
        Q_OBJECT
    
        QVector<QPair<double,double>> vec_;
    
        double m_xMin;
        double m_xMax;
        double m_yMin;
        double m_yMax;
    
        Q_PROPERTY (double xMin READ get_xMin WRITE set_xMin NOTIFY xMinChanged)
        Q_PROPERTY (double xMax READ get_xMax WRITE set_xMax NOTIFY xMaxChanged)
        Q_PROPERTY (double yMin READ get_yMin WRITE set_yMin NOTIFY yMinChanged)
        Q_PROPERTY (double yMax READ get_yMax WRITE set_yMax NOTIFY yMaxChanged)
    
    public:
        explicit ChartModel(QObject *parent = nullptr);
    
        int rowCount(const QModelIndex &parent = QModelIndex()) const override;
        int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
        //    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
    
        double get_xMin() const;
        double get_xMax() const;
        double get_yMin() const;
        double get_yMax() const;
    
    public slots:
        bool set_xMin(double val);
        bool set_xMax(double val);
        bool set_yMin(double val);
        bool set_yMax(double val);
    
        void appendData();
    
    signals:
        void xMinChanged(double);
        void xMaxChanged(double);
        void yMinChanged(double);
        void yMaxChanged(double);
    };
    
    #endif // CHARTMODEL_H
    
    

    chartmodel.cpp

    #include "chartmodel.h"
    
    ChartModel::ChartModel(QObject *parent) : QAbstractTableModel(parent)
    {
        m_xMin = 0.;
        m_xMax = 1.;
        m_yMin = 0.;
        m_yMax = 1.;
    }
    
    int ChartModel::rowCount(const QModelIndex & /* parent */) const
    {
        return vec_.size();
    }
    
    int ChartModel::columnCount(const QModelIndex & /* parent */) const
    {
        return 2;
    }
    
    QVariant ChartModel::data(const QModelIndex &index, int role) const
    {
        if (!index.isValid() || role != Qt::DisplayRole)
            return QVariant();
    
        if (index.column() == 0){
            return vec_.at(index.row()).first;
        }
        if (index.column() == 1){
            return vec_.at(index.row()).second;
        }
        return QVariant();
    }
    
    double ChartModel::get_xMin() const
    {
        return m_xMin;
    }
    
    double ChartModel::get_xMax() const
    {
        return m_xMax;
    }
    double ChartModel::get_yMin() const
    {
        return m_yMin;
    }
    
    double ChartModel::get_yMax() const
    {
        return m_yMax;
    }
    
    bool ChartModel::set_xMin(double val)
    {
        bool ret = false;
        if ((ret = (m_xMin != val))) {
            m_xMin = val;
            emit xMinChanged (m_xMin);
        }
        return ret;
    }
    
    bool ChartModel::set_xMax(double val)
    {
        bool ret = false;
        if ((ret = (m_xMax != val))) {
            m_xMax = val;
            emit xMaxChanged (m_xMax);
        }
        return ret;
    }
    
    bool ChartModel::set_yMin(double val)
    {
        bool ret = false;
        if ((ret = (m_yMin != val))) {
            m_yMin = val;
            emit yMinChanged (m_yMin);
        }
        return ret;
    }
    
    bool ChartModel::set_yMax(double val)
    {
        bool ret = false;
        if ((ret = (m_yMax != val))) {
            m_yMax = val;
            emit yMaxChanged (m_yMax);
        }
        return ret;
    }
    
    void ChartModel::appendData()
    {
    
        int const nbData = 1+qRound(10.*double(qrand())/double(RAND_MAX));
        int const vecSize = vec_.size();
    
        if (!vecSize){
            m_xMin = qInf();
            m_xMax = -qInf();
            m_yMin = qInf();
            m_yMax = -qInf();
        }
    
        beginInsertRows(QModelIndex (), vecSize, vecSize+nbData);
    
        for(int seed = 0 ; seed <  nbData; ++seed){
            double const xVal = vec_.size();
            double const yVal = double(qrand())/double(RAND_MAX);
            set_xMin(qMin(m_xMin, xVal));
            set_xMax(qMax(m_xMax, xVal));
            set_yMin(qMin(m_yMin, yVal));
            set_yMax(qMax(m_yMax, yVal));
            vec_.append(qMakePair<double, double>(xVal, yVal));
        }
        endInsertRows();
    }
    
    

    main.qml

    import QtQuick 2.10
    import QtQuick.Window 2.10
    import QtCharts 2.0
    import MainLib 1.0
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        property ChartModel chartModel : ChartModel{}
    
        ChartView {
            id : chart
            anchors.fill: parent
            antialiasing: true
            animationOptions: ChartView.AllAnimations
    
            SplineSeries {
                id : serie1
    
                axisX : ValueAxis {
                    id: xAxis
                    min: chartModel.xMin
                    max: chartModel.xMax
                }
    
                axisY : ValueAxis {
                    id: yAxis
                    min: chartModel.yMin
                    max: chartModel.yMax
                }
    
                VXYModelMapper {
                    id: mapper
                    xColumn: 0
                    yColumn: 1
                    model: chartModel
                }
            }
            MouseArea{
                anchors.fill : parent
                onClicked: {
                    chartModel.appendData()
                }
            }
        }
    }
    
    


  • @Winz for the brilliant example you mentioned, I see the chart is compressing the graph, If I want to let the screen move to display only the last 5 points, what I need to change!?



  • The "viewport" of the ChartView is defined by the properties ValueAxis:min and ValueAxis:max for both X and Y axis. In this example those properties are binded with the properties xMin, xMax, yMin, yMax of the ChartModel. Yo can also set them with constant or with javascript expressions.

    Below an update of the chartModel.cpp file that rescale the ChartView to the 5 last values of the model

    #include "chartmodel.h"
    
    ChartModel::ChartModel(QObject *parent) : QAbstractTableModel(parent)
    {
        m_xMin = 0.;
        m_xMax = 1.;
        m_yMin = 0.;
        m_yMax = 1.;
    }
    
    int ChartModel::rowCount(const QModelIndex & /* parent */) const
    {
        return vec_.size();
    }
    
    int ChartModel::columnCount(const QModelIndex & /* parent */) const
    {
        return 2;
    }
    
    QVariant ChartModel::data(const QModelIndex &index, int role) const
    {
        if (!index.isValid() || role != Qt::DisplayRole)
            return QVariant();
    
        if (index.column() == 0){
            return vec_.at(index.row()).first;
        }
        if (index.column() == 1){
            return vec_.at(index.row()).second;
        }
        return QVariant();
    }
    
    double ChartModel::get_xMin() const
    {
        return m_xMin;
    }
    
    double ChartModel::get_xMax() const
    {
        return m_xMax;
    }
    double ChartModel::get_yMin() const
    {
        return m_yMin;
    }
    
    double ChartModel::get_yMax() const
    {
        return m_yMax;
    }
    
    bool ChartModel::set_xMin(double val)
    {
        bool ret = false;
        if ((ret = (m_xMin != val))) {
            m_xMin = val;
            emit xMinChanged (m_xMin);
        }
        return ret;
    }
    
    bool ChartModel::set_xMax(double val)
    {
        bool ret = false;
        if ((ret = (m_xMax != val))) {
            m_xMax = val;
            emit xMaxChanged (m_xMax);
        }
        return ret;
    }
    
    bool ChartModel::set_yMin(double val)
    {
        bool ret = false;
        if ((ret = (m_yMin != val))) {
            m_yMin = val;
            emit yMinChanged (m_yMin);
        }
        return ret;
    }
    
    bool ChartModel::set_yMax(double val)
    {
        bool ret = false;
        if ((ret = (m_yMax != val))) {
            m_yMax = val;
            emit yMaxChanged (m_yMax);
        }
        return ret;
    }
    
    void ChartModel::appendData()
    {
    
        int const nbData = 1+qRound(10.*double(qrand())/double(RAND_MAX));
        int const vecSize = vec_.size();
    
        //    if (!vecSize){
        m_xMin = qInf();
        m_xMax = -qInf();
        m_yMin = qInf();
        m_yMax = -qInf();
        //    }
    
        beginInsertRows(QModelIndex (), vecSize, vecSize+nbData);
    
        for(int seed = 0 ; seed <  nbData; ++seed){
            double const xVal = vec_.size();
            double const yVal = double(qrand())/double(RAND_MAX);
    
    //        set_xMin(qMin(m_xMin, xVal));
    //        set_xMax(qMax(m_xMax, xVal));
    //        set_yMin(qMin(m_yMin, yVal));
    //        set_yMax(qMax(m_yMax, yVal));
    
            vec_.append(qMakePair<double, double>(xVal, yVal));
        }
        
        for(int seed = (vecSize < 5 ? 0:vecSize-5) ; seed <  vecSize; ++seed){
            double const xVal = vec_.at(seed).first;
            double const yVal = vec_.at(seed).second;
            set_xMin(qMin(m_xMin, xVal));
            set_xMax(qMax(m_xMax, xVal));
            set_yMin(qMin(m_yMin, yVal));
            set_yMax(qMax(m_yMax, yVal));
        }
    
        endInsertRows();
    }
    




Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.