From dc14479d561196e19417c4ecf78e847ec4b43b7c Mon Sep 17 00:00:00 2001 From: David Llewellyn-Jones Date: Sun, 22 Jul 2018 15:47:15 +0100 Subject: [PATCH] Add graphs generated from journey data Average journey time for each weekday. Average number of cyclists passed for each weekday. --- harbour-pedalo.pro | 8 ++++-- qml/pages/Stats.qml | 21 +++++++++----- src/harbour-pedalo.cpp | 19 +++++-------- src/stats.cpp | 50 +++++++++++++++++++++++++++++++- src/stats.h | 27 ++++++++++++++---- src/statsmodel.cpp | 32 +++++++++++++++++---- src/statsmodel.h | 15 +++++++--- src/statsweekdayave.cpp | 52 ++++++++++++++++++++++++++++++++++ src/statsweekdayave.h | 18 ++++++++++++ src/statsweekdaycongestion.cpp | 50 ++++++++++++++++++++++++++++++++ src/statsweekdaycongestion.h | 19 +++++++++++++ 11 files changed, 274 insertions(+), 37 deletions(-) create mode 100644 src/statsweekdayave.cpp create mode 100644 src/statsweekdayave.h create mode 100644 src/statsweekdaycongestion.cpp create mode 100644 src/statsweekdaycongestion.h diff --git a/harbour-pedalo.pro b/harbour-pedalo.pro index 7c12a39..7c01192 100644 --- a/harbour-pedalo.pro +++ b/harbour-pedalo.pro @@ -35,7 +35,9 @@ SOURCES += src/harbour-pedalo.cpp \ src/imageprovider.cpp \ src/graph.cpp \ src/statsmodel.cpp \ - src/stats.cpp + src/stats.cpp \ + src/statsweekdayave.cpp \ + src/statsweekdaycongestion.cpp DISTFILES += qml/harbour-pedalo.qml \ qml/cover/CoverPage.qml \ @@ -79,4 +81,6 @@ HEADERS += \ src/imageprovider.h \ src/graph.h \ src/statsmodel.h \ - src/stats.h + src/stats.h \ + src/statsweekdayave.h \ + src/statsweekdaycongestion.h diff --git a/qml/pages/Stats.qml b/qml/pages/Stats.qml index e082b0f..8e13f97 100644 --- a/qml/pages/Stats.qml +++ b/qml/pages/Stats.qml @@ -78,9 +78,16 @@ Page { height: (isPortrait ? statsPage.height / 2.0 : statsPage.height) - Theme.paddingLarge itemWidth: width clip: true + anchors.left: isPortrait ? statsColumn.left : statsColumn.right + anchors.leftMargin: 0 y: (isPortrait ? (statsPage.height / 2.0) : statsColumn.y) + onModelChanged: { + console.log("Model changed"); + model.updateAll(); + } + model: statsmodel delegate: Rectangle { width: graphsView.itemWidth @@ -89,25 +96,25 @@ Page { SectionHeader { id: sectionHeaderItem - text: "item " + index + text: title } Graph { id: graph - width: parent.width - 2 * Theme.horizontalPageMargin + width: parent.width - Theme.horizontalPageMargin anchors.top: sectionHeaderItem.bottom height: (isPortrait ? (statsPage.height / 2.0) - Theme.paddingLarge : statsPage.height - Theme.paddingLarge - headerItem.height) - sectionHeaderItem.height - anchors.horizontalCenter: parent.horizontalCenter + anchors.left: parent.left model: values labelsx: labels //labelsy: ["0%", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"] - unitsy: "%" + unitsy: units primary: Theme.primaryColor secondary: Theme.highlightColor highlight: Theme.highlightColor - miny: 0.0 - maxy: 1.0 - stepy: 0.1 + miny: minval + maxy: maxval + stepy: step gap: 0.1 fontsize: Theme.fontSizeExtraSmall /* diff --git a/src/harbour-pedalo.cpp b/src/harbour-pedalo.cpp index abbe2be..35fc77f 100644 --- a/src/harbour-pedalo.cpp +++ b/src/harbour-pedalo.cpp @@ -12,6 +12,8 @@ #include "settings.h" #include "imageprovider.h" #include "graph.h" +#include "statsweekdayave.h" +#include "statsweekdaycongestion.h" #include "harbour-pedalo.h" @@ -45,19 +47,12 @@ int main(int argc, char *argv[]) Settings::getInstance().loadSettings(); StatsModel statsmodel; - Stats stats; - QList data{0.1, 0.1, 0.2}; - QStringList labels{"A", "B", "C"}; - stats.setValues(data); - stats.setLabels(labels); - statsmodel.addStats(stats); - - data = QList{0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.5}; - labels = QStringList{"M", "T", "W", "Th", "F", "S", "Su"}; - stats.setValues(data); - stats.setLabels(labels); - statsmodel.addStats(stats); + StatsWeekdayAve statsweekdayave(&journeys); + statsmodel.addStats(statsweekdayave); + + StatsWeekdayCongestion statsweekdaycongestion(&journeys); + statsmodel.addStats(statsweekdaycongestion); QFile file; file.setFileName(Settings::getConfigDir() + "/journeys.csv"); diff --git a/src/stats.cpp b/src/stats.cpp index c858ccb..1a80ab2 100644 --- a/src/stats.cpp +++ b/src/stats.cpp @@ -1,10 +1,23 @@ #include "stats.h" -Stats::Stats() +Stats::Stats() : + title("Empty graph"), + units("%"), + minval(0.0), + maxval(1.0), + step(0.1) { } +void Stats::update() { + // Do nothing +} + +QString Stats::getTitle() const { + return title; +} + QStringList Stats::getLabels() const { return labels; } @@ -13,6 +26,26 @@ QList Stats::getValues() const { return values; } +QString Stats::getUnits() const { + return units; +} + +float Stats::getMinVal() const { + return minval; +} + +float Stats::getMaxVal() const { + return maxval; +} + +float Stats::getStep() const { + return step; +} + +void Stats::setTitle(QString &value) { + title = value; +} + void Stats::setLabels(QStringList &value) { labels = value; } @@ -21,3 +54,18 @@ void Stats::setValues(QList &value) { values = value; } +void Stats::setUnits(QString &value) { + units = value; +} + +void Stats::setMinVal(float value) { + minval = value; +} + +void Stats::setMaxVal(float value) { + maxval = value; +} + +void Stats::setStep(float value) { + step = value; +} diff --git a/src/stats.h b/src/stats.h index 12fb41e..73accfd 100644 --- a/src/stats.h +++ b/src/stats.h @@ -8,15 +8,32 @@ class Stats public: Stats(); - QStringList getLabels() const; - QList getValues() const; + virtual void update(); - void setLabels(QStringList &value); - void setValues(QList &value); + virtual QString getTitle() const; + virtual QStringList getLabels() const; + virtual QList getValues() const; + virtual QString getUnits() const; + virtual float getMinVal() const; + virtual float getMaxVal() const; + virtual float getStep() const; -private: + virtual void setTitle(QString &value); + virtual void setLabels(QStringList &value); + virtual void setValues(QList &value); + virtual void setUnits(QString &value); + virtual void setMinVal(float value); + virtual void setMaxVal(float value); + virtual void setStep(float value); + +protected: + QString title; QStringList labels; QList values; + QString units; + float minval; + float maxval; + float step; }; #endif // STATS_H diff --git a/src/statsmodel.cpp b/src/statsmodel.cpp index 52090c4..b6a2ef8 100644 --- a/src/statsmodel.cpp +++ b/src/statsmodel.cpp @@ -1,12 +1,17 @@ #include "statsmodel.h" StatsModel::StatsModel(QObject *parent) : QAbstractListModel(parent) { + roles[TitleRole] = "title"; roles[ValuesRole] = "values"; roles[LabelsRole] = "labels"; + roles[UnitsRole] = "units"; + roles[MinValRole] = "minval"; + roles[MaxValRole] = "maxval"; + roles[StepRole] = "step"; } -void StatsModel::addStats(const Stats &stats) { - this->stats.append(stats); +void StatsModel::addStats(Stats &stats) { + this->stats.append(&stats); } QHash StatsModel::roleNames() const { @@ -22,11 +27,21 @@ QVariant StatsModel::data(const QModelIndex & index, int role) const { if (index.row() < 0 || index.row() > stats.count()) return QVariant(); - const Stats &stat = stats[index.row()]; - if (role == ValuesRole) - return QVariant::fromValue>(stat.getValues()); + const Stats *stat = stats[index.row()]; + if (role == TitleRole) + return stat->getTitle(); + else if (role == ValuesRole) + return QVariant::fromValue>(stat->getValues()); else if (role == LabelsRole) - return stat.getLabels(); + return stat->getLabels(); + else if (role == UnitsRole) + return stat->getUnits(); + else if (role == MinValRole) + return stat->getMinVal(); + else if (role == MaxValRole) + return stat->getMaxVal(); + else if (role == StepRole) + return stat->getStep(); return QVariant(); } @@ -34,3 +49,8 @@ void StatsModel::clear() { stats.clear(); } +void StatsModel::updateAll() { + foreach (Stats * stat, stats) { + stat->update(); + } +} diff --git a/src/statsmodel.h b/src/statsmodel.h index 2c9991a..662cf79 100644 --- a/src/statsmodel.h +++ b/src/statsmodel.h @@ -11,15 +11,20 @@ class StatsModel : public QAbstractListModel Q_OBJECT public: enum StatsRoles { - ValuesRole = Qt::UserRole + 1, - LabelsRole + TitleRole = Qt::UserRole + 1, + ValuesRole, + LabelsRole, + UnitsRole, + MinValRole, + MaxValRole, + StepRole }; QHash roleNames() const; StatsModel(QObject *parent = 0); - void addStats(const Stats &stats); + void addStats(Stats &stats); int rowCount(const QModelIndex & parent = QModelIndex()) const; @@ -27,9 +32,11 @@ public: void clear(); + Q_INVOKABLE void updateAll(); + private: QHash roles; - QList stats; + QList stats; }; #endif // STATSMODEL_H diff --git a/src/statsweekdayave.cpp b/src/statsweekdayave.cpp new file mode 100644 index 0000000..63e595e --- /dev/null +++ b/src/statsweekdayave.cpp @@ -0,0 +1,52 @@ +#include + +#include "statsweekdayave.h" + +StatsWeekdayAve::StatsWeekdayAve(JourneyModel * journeys) : + journeys(journeys) +{ + title = "Average journey time (mins)"; + units = ""; + labels = QStringList{"M", "T", "W", "Th", "F", "S", "Su"}; +} + +void StatsWeekdayAve::update() { + double duration[7]; + unsigned int count[7]; + int pos; + + qDebug() << "Calculating values"; + values.clear(); + + for (pos = 0; pos < 7; pos++) { + duration[pos] = 0.0; + count[pos] = 0u; + } + + foreach (Journey const &journey, journeys->getData()) { + QDate date = journey.getStartDate(); + int dayofweek = date.dayOfWeek() - 1; + if (dayofweek >= 0) { + duration[dayofweek] += journey.getDuration(); + count[dayofweek]++; + } + } + + maxval = 0.0; + for (pos = 0; pos < 7; pos++) { + float result = 0.0f; + if (count[pos] > 0) { + result = ((duration[pos] / 60.0) / (double)count[pos]); + } + if (result > maxval) { + maxval = result; + } + values << result; + } + + step = qRound(maxval / 5.0); + + qDebug() << "Calculated values"; +} + + diff --git a/src/statsweekdayave.h b/src/statsweekdayave.h new file mode 100644 index 0000000..1a36d32 --- /dev/null +++ b/src/statsweekdayave.h @@ -0,0 +1,18 @@ +#ifndef STATSWEEKDAYAVE_H +#define STATSWEEKDAYAVE_H + +#include "journeymodel.h" + +#include "stats.h" + +class StatsWeekdayAve : public Stats +{ +public: + StatsWeekdayAve(JourneyModel * journeys); + + void update(); +private: + JourneyModel * journeys; +}; + +#endif // STATSWEEKDAYAVE_H diff --git a/src/statsweekdaycongestion.cpp b/src/statsweekdaycongestion.cpp new file mode 100644 index 0000000..685e175 --- /dev/null +++ b/src/statsweekdaycongestion.cpp @@ -0,0 +1,50 @@ +#include + +#include "statsweekdaycongestion.h" + +StatsWeekdayCongestion::StatsWeekdayCongestion(JourneyModel * journeys) : + journeys(journeys) +{ + title = "Congested days (cycles passed)"; + units = ""; + labels = QStringList{"M", "T", "W", "Th", "F", "S", "Su"}; +} + +void StatsWeekdayCongestion::update() { + quint32 passed[7]; + unsigned int count[7]; + int pos; + + qDebug() << "Calculating values"; + values.clear(); + + for (pos = 0; pos < 7; pos++) { + passed[pos] = 0u; + count[pos] = 0u; + } + + foreach (Journey const &journey, journeys->getData()) { + QDate date = journey.getStartDate(); + int dayofweek = date.dayOfWeek() - 1; + if (dayofweek >= 0) { + passed[dayofweek] += journey.getOvertook() + journey.getOvertakenBy(); + count[dayofweek]++; + } + } + + maxval = 0.0; + for (pos = 0; pos < 7; pos++) { + float result = 0.0f; + if (count[pos] > 0) { + result = ((double)passed[pos] / (double)count[pos]); + } + if (result > maxval) { + maxval = result; + } + values << result; + } + + step = qRound(maxval / 5.0); + + qDebug() << "Calculated values"; +} diff --git a/src/statsweekdaycongestion.h b/src/statsweekdaycongestion.h new file mode 100644 index 0000000..2b0dda2 --- /dev/null +++ b/src/statsweekdaycongestion.h @@ -0,0 +1,19 @@ +#ifndef STATSWEEKDAYCONGESTION_H +#define STATSWEEKDAYCONGESTION_H + +#include "journeymodel.h" + +#include "stats.h" + +class StatsWeekdayCongestion : public Stats +{ +public: + StatsWeekdayCongestion(JourneyModel * journeys); + + void update(); + +private: + JourneyModel * journeys; +}; + +#endif // STATSWEEKDAYCONGESTION_H -- 2.25.1