Graph Gallery

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

#include "rainfalldata.h"
#include <QtCore/qfile.h>
#include <QtCore/qtextstream.h>
#include <QtGraphs/q3dscene.h>
#include <QtGraphs/q3dtheme.h>
#include <QtGraphs/qbar3dseries.h>

using namespace Qt::StringLiterals;

RainfallData::RainfallData()
{
    // In data file the months are in numeric format, so create custom list
    for (int i = 1; i <= 12; ++i)
        m_numericMonths << QString::number(i);

    m_columnCount = m_numericMonths.size();

    updateYearsList(2010, 2022);

    // Create proxy and series
    m_proxy = new VariantBarDataProxy;
    m_series = new QBar3DSeries(m_proxy);

    m_series->setItemLabelFormat(u"%.1f mm"_s);

    // Create the axes
    m_rowAxis = new QCategory3DAxis(this);
    m_colAxis = new QCategory3DAxis(this);
    m_valueAxis = new QValue3DAxis(this);
    m_rowAxis->setAutoAdjustRange(true);
    m_colAxis->setAutoAdjustRange(true);
    m_valueAxis->setAutoAdjustRange(true);

    // Set axis labels and titles
    QStringList months{"January",
                       "February",
                       "March",
                       "April",
                       "May",
                       "June",
                       "July",
                       "August",
                       "September",
                       "October",
                       "November",
                       "December"};
    m_rowAxis->setTitle("Year");
    m_colAxis->setTitle("Month");
    m_valueAxis->setTitle("rainfall (mm)");
    m_valueAxis->setSegmentCount(5);
    m_rowAxis->setLabels(m_years);
    m_colAxis->setLabels(months);
    m_rowAxis->setTitleVisible(true);
    m_colAxis->setTitleVisible(true);
    m_valueAxis->setTitleVisible(true);

    addDataSet();
}

RainfallData::~RainfallData()
{
    delete m_mapping;
}

void RainfallData::updateYearsList(int start, int end)
{
    m_years.clear();

    for (int i = start; i <= end; ++i)
        m_years << QString::number(i);

    m_rowCount = m_years.size();
}

void RainfallData::addDataSet()
{
    // Create a new variant data set and data item list
    m_dataSet = new VariantDataSet;
    auto *itemList = new VariantDataItemList;

    // Read data from a data file into the data item list
    QFile dataFile(":/data/raindata.txt");
    if (dataFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QTextStream stream(&dataFile);
        while (!stream.atEnd()) {
            QString line = stream.readLine();
            if (line.startsWith('#')) // Ignore comments
                continue;
            const auto strList = QStringView{line}.split(',', Qt::SkipEmptyParts);
            // Each line has three data items: Year, month, and rainfall value
            if (strList.size() < 3) {
                qWarning() << "Invalid row read from data:" << line;
                continue;
            }
            // Store year and month as strings, and rainfall value as double
            // into a variant data item and add the item to the item list.
            auto *newItem = new VariantDataItem;
            for (int i = 0; i < 2; ++i)
                newItem->append(strList.at(i).trimmed().toString());
            newItem->append(strList.at(2).trimmed().toDouble());
            itemList->append(newItem);
        }
    } else {
        qWarning() << "Unable to open data file:" << dataFile.fileName();
    }

    // Add items to the data set and set it to the proxy
    m_dataSet->addItems(itemList);
    m_proxy->setDataSet(m_dataSet);

    // Create new mapping for the data and set it to the proxy
    m_mapping = new VariantBarDataMapping(0, 1, 2, m_years, m_numericMonths);
    m_proxy->setMapping(m_mapping);
}