Commit ecba83ee authored by Volker Krause's avatar Volker Krause
Browse files

Add numeric aggregation model for box plots.

parent 4635ac5a
......@@ -6,6 +6,7 @@ set(analyzer_srcs
datamodel.cpp
main.cpp
mainwindow.cpp
numericaggregationmodel.cpp
product.cpp
productmodel.cpp
productschemaentry.cpp
......
......@@ -69,14 +69,15 @@ QVariant CategoryAggregationModel::data(const QModelIndex& index, int role) cons
if (!index.isValid() || !m_sourceModel)
return {};
if (role == TimeAggregationModel::MaximumValueRole)
return m_maxValue;
if (index.column() == 0) {
const auto srcIdx = m_sourceModel->index(index.row(), 0);
return m_sourceModel->data(srcIdx, role);
}
if (role == Qt::DisplayRole) {
return m_data[index.row() * m_categories.size() + index.column() - 1];
} else if (role == TimeAggregationModel::MaximumValueRole) {
return m_maxValue;
}
return {};
......
......@@ -24,6 +24,7 @@
#include "chart.h"
#include "connectdialog.h"
#include "datamodel.h"
#include "numericaggregationmodel.h"
#include "productmodel.h"
#include "restclient.h"
#include "serverinfo.h"
......@@ -281,6 +282,16 @@ void MainWindow::productSelected()
ui->chartType->addItem(schemaEntry.name(), QVariant::fromValue(model));
break;
}
case ProductSchemaEntry::IntegerType:
{
auto model = new NumericAggregationModel(this);
model->setSourceModel(m_timeAggregationModel);
model->setAggregationValue(schemaEntry.name());
m_aggregationModels.push_back(model);
m_aggregatedDataModel->addSourceModel(model, schemaEntry.name());
ui->chartType->addItem(schemaEntry.name(), QVariant::fromValue(model));
break;
}
}
}
}
......
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "numericaggregationmodel.h"
#include "sample.h"
#include "timeaggregationmodel.h"
using namespace UserFeedback::Analyzer;
NumericAggregationModel::NumericAggregationModel(QObject *parent) :
QAbstractTableModel(parent)
{
}
NumericAggregationModel::~NumericAggregationModel() = default;
void NumericAggregationModel::setSourceModel(QAbstractItemModel* model)
{
Q_ASSERT(model);
m_sourceModel = model;
connect(model, &QAbstractItemModel::modelReset, this, &NumericAggregationModel::recompute);
recompute();
}
void NumericAggregationModel::setAggregationValue(const QString& aggrValue)
{
m_aggrValue = aggrValue;
recompute();
}
int NumericAggregationModel::columnCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return 6;
}
int NumericAggregationModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid() || !m_sourceModel)
return 0;
return m_sourceModel->rowCount();
}
QVariant NumericAggregationModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid() || !m_sourceModel)
return {};
if (role == TimeAggregationModel::MaximumValueRole)
return m_maxValue;
if (index.column() == 0) {
const auto srcIdx = m_sourceModel->index(index.row(), 0);
return m_sourceModel->data(srcIdx, role);
}
if (role == Qt::DisplayRole) {
const auto d = m_data.at(index.row());
switch (index.column()) {
case 1: return d.lowerExtreme;
case 2: return d.lowerQuartile;
case 3: return d.median;
case 4: return d.upperQuartile;
case 5: return d.upperExtreme;
}
}
return {};
}
QVariant NumericAggregationModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole && m_sourceModel) {
switch (section) {
case 0: return m_sourceModel->headerData(section, orientation, role);
case 1: return tr("Lower Extreme");
case 2: return tr("Lower Quartile");
case 3: return tr("Median");
case 4: return tr("Upper Quartile");
case 5: return tr("Upper Extreme");
}
}
return QAbstractTableModel::headerData(section, orientation, role);
}
void NumericAggregationModel::recompute()
{
if (!m_sourceModel)
return;
const auto rowCount = m_sourceModel->rowCount();
beginResetModel();
m_data.clear();
m_maxValue = 0;
if (rowCount <= 0 || m_aggrValue.isEmpty()) {
endResetModel();
return;
}
m_data.reserve(rowCount);
QVector<double> values;
for (int row = 0; row < rowCount; ++row) {
const auto samples = m_sourceModel->index(row, 0).data(TimeAggregationModel::SamplesRole).value<QVector<Sample>>();
values.clear();
values.reserve(samples.size());
foreach (const auto &sample, samples) {
const auto v = sample.value(m_aggrValue).toDouble();
values.push_back(v);
}
std::sort(values.begin(), values.end());
Data d;
if (values.size() > 0) {
d.lowerExtreme = values.at(0);
d.lowerQuartile = values.at(values.size() / 4);
d.median = values.at(values.size() / 2);
d.upperQuartile = values.at(values.size() * 3 / 4);
d.upperExtreme = values.last();
m_maxValue = std::max(m_maxValue, d.upperExtreme);
}
m_data.push_back(d);
}
endResetModel();
}
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USERFEEDBACK_ANALYZER_NUMERICAGGREGATIONMODEL_H
#define USERFEEDBACK_ANALYZER_NUMERICAGGREGATIONMODEL_H
#include <QAbstractTableModel>
namespace UserFeedback {
namespace Analyzer {
class NumericAggregationModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit NumericAggregationModel(QObject *parent = nullptr);
~NumericAggregationModel();
void setSourceModel(QAbstractItemModel *model);
void setAggregationValue(const QString &aggrValue);
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
private:
void recompute();
QAbstractItemModel *m_sourceModel = nullptr;
QString m_aggrValue;
struct Data {
double lowerExtreme = 0.0;
double lowerQuartile = 0.0;
double median = 0.0;
double upperQuartile = 0.0;
double upperExtreme = 0.0;
};
QVector<Data> m_data;
double m_maxValue = 0.0;
};
}
}
#endif // USERFEEDBACK_ANALYZER_NUMERICAGGREGATIONMODEL_H
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment