Add level distribution chart, more adjustments
This commit is contained in:
parent
9b09637b47
commit
c33e72f404
4 changed files with 342 additions and 92 deletions
|
@ -6,8 +6,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>697</width>
|
<width>776</width>
|
||||||
<height>349</height>
|
<height>445</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -15,19 +15,131 @@
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
<number>0</number>
|
<number>4</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="topMargin">
|
<property name="topMargin">
|
||||||
<number>0</number>
|
<number>4</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="rightMargin">
|
<property name="rightMargin">
|
||||||
<number>0</number>
|
<number>4</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>4</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QChartView" name="chartView"/>
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<widget class="QWidget" name="tabSpecies" native="true">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Species Distribution</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QChartView" name="chartView_SpeciesDistribution">
|
||||||
|
<property name="renderHints">
|
||||||
|
<set>QPainter::Antialiasing</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tabLevels" native="true">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Level Distribution</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Plain</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_Group">
|
||||||
|
<property name="text">
|
||||||
|
<string>Group</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBox_Group">
|
||||||
|
<property name="editable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Species</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBox_Species">
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="insertPolicy">
|
||||||
|
<enum>QComboBox::NoInsert</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QChartView" name="chartView_LevelDistribution">
|
||||||
|
<property name="renderHints">
|
||||||
|
<set>QPainter::Antialiasing</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "encountertablemodel.h"
|
#include "encountertablemodel.h"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QtCharts>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class WildMonChart;
|
class WildMonChart;
|
||||||
|
@ -18,11 +19,40 @@ public:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setTable(const EncounterTableModel *table);
|
void setTable(const EncounterTableModel *table);
|
||||||
void updateChart();
|
void createCharts();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::WildMonChart *ui;
|
Ui::WildMonChart *ui;
|
||||||
const EncounterTableModel *table;
|
const EncounterTableModel *table;
|
||||||
|
|
||||||
|
QStringList groupNames;
|
||||||
|
QMap<int, QString> tableIndexToGroupName;
|
||||||
|
|
||||||
|
struct Summary {
|
||||||
|
double speciesFrequency = 0.0;
|
||||||
|
QMap<int, double> levelFrequencies;
|
||||||
|
};
|
||||||
|
|
||||||
|
int tableMinLevel;
|
||||||
|
int tableMaxLevel;
|
||||||
|
|
||||||
|
// GroupedData maps a group name ("old_rod", "good_rod"...)
|
||||||
|
// to any summarized data needed for the charts.
|
||||||
|
typedef QMap<QString, Summary> GroupedData;
|
||||||
|
|
||||||
|
QMap<QString, GroupedData> speciesToGroupedData;
|
||||||
|
|
||||||
|
QStringList getSpeciesNames() const;
|
||||||
|
double getSpeciesFrequency(const QString&, const QString&) const;
|
||||||
|
QMap<int, double> getLevelFrequencies(const QString &, const QString &) const;
|
||||||
|
bool usesGroupLabels() const;
|
||||||
|
|
||||||
|
void clearTableData();
|
||||||
|
void readTable();
|
||||||
|
void createSpeciesDistributionChart();
|
||||||
|
void createLevelDistributionChart();
|
||||||
|
|
||||||
|
void stopChartAnimation();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WILDMONCHART_H
|
#endif // WILDMONCHART_H
|
||||||
|
|
|
@ -2578,6 +2578,8 @@ void MainWindow::on_pushButton_SummaryChart_clicked() {
|
||||||
QTableView *table = this->editor->getCurrentWildMonTable();
|
QTableView *table = this->editor->getCurrentWildMonTable();
|
||||||
EncounterTableModel *data = table ? static_cast<EncounterTableModel *>(table->model()) : nullptr;
|
EncounterTableModel *data = table ? static_cast<EncounterTableModel *>(table->model()) : nullptr;
|
||||||
this->wildMonChart = new WildMonChart(this, data);
|
this->wildMonChart = new WildMonChart(this, data);
|
||||||
|
} else {
|
||||||
|
this->wildMonChart->createCharts();
|
||||||
}
|
}
|
||||||
openSubWindow(this->wildMonChart);
|
openSubWindow(this->wildMonChart);
|
||||||
}
|
}
|
||||||
|
@ -3027,6 +3029,10 @@ bool MainWindow::closeSupplementaryWindows() {
|
||||||
return false;
|
return false;
|
||||||
this->customScriptsEditor = nullptr;
|
this->customScriptsEditor = nullptr;
|
||||||
|
|
||||||
|
if (this->wildMonChart && !this->wildMonChart->close())
|
||||||
|
return false;
|
||||||
|
this->wildMonChart = nullptr;
|
||||||
|
|
||||||
if (this->projectSettingsEditor) this->projectSettingsEditor->closeQuietly();
|
if (this->projectSettingsEditor) this->projectSettingsEditor->closeQuietly();
|
||||||
this->projectSettingsEditor = nullptr;
|
this->projectSettingsEditor = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -4,16 +4,16 @@
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#include <QtCharts>
|
|
||||||
|
|
||||||
// TODO: Make level range its own chart(s)?
|
// TODO: Make level range its own chart(s)?
|
||||||
// TODO: Draw species icons below legend icons?
|
// TODO: Draw species icons below legend icons?
|
||||||
// TODO: Add hover behavior to display species name (and click prompt?)
|
// TODO: NoScrollComboBoxes
|
||||||
|
|
||||||
|
static const QString baseWindowTitle = QString("Wild Pokémon Summary Charts");
|
||||||
|
|
||||||
struct ChartData {
|
struct ChartData {
|
||||||
int minLevel;
|
int minLevel;
|
||||||
int maxLevel;
|
int maxLevel;
|
||||||
QMap<int, double> values; // One value for each wild encounter group
|
QMap<QString, double> valueMap; // One value for each wild encounter group
|
||||||
};
|
};
|
||||||
|
|
||||||
WildMonChart::WildMonChart(QWidget *parent, const EncounterTableModel *table) :
|
WildMonChart::WildMonChart(QWidget *parent, const EncounterTableModel *table) :
|
||||||
|
@ -24,7 +24,8 @@ WildMonChart::WildMonChart(QWidget *parent, const EncounterTableModel *table) :
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
setWindowFlags(Qt::Window);
|
setWindowFlags(Qt::Window);
|
||||||
|
|
||||||
ui->chartView->setRenderHint(QPainter::Antialiasing);
|
connect(ui->comboBox_Species, &QComboBox::currentTextChanged, this, &WildMonChart::createLevelDistributionChart);
|
||||||
|
connect(ui->comboBox_Group, &QComboBox::currentTextChanged, this, &WildMonChart::createLevelDistributionChart);
|
||||||
|
|
||||||
setTable(table);
|
setTable(table);
|
||||||
};
|
};
|
||||||
|
@ -35,95 +36,132 @@ WildMonChart::~WildMonChart() {
|
||||||
|
|
||||||
void WildMonChart::setTable(const EncounterTableModel *table) {
|
void WildMonChart::setTable(const EncounterTableModel *table) {
|
||||||
this->table = table;
|
this->table = table;
|
||||||
updateChart();
|
readTable();
|
||||||
|
createCharts();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const bool showLevelRange = false;
|
void WildMonChart::clearTableData() {
|
||||||
|
this->groupNames.clear();
|
||||||
|
this->tableIndexToGroupName.clear();
|
||||||
|
this->speciesToGroupedData.clear();
|
||||||
|
this->tableMinLevel = INT_MAX;
|
||||||
|
this->tableMaxLevel = INT_MIN;
|
||||||
|
setWindowTitle(baseWindowTitle);
|
||||||
|
}
|
||||||
|
|
||||||
void WildMonChart::updateChart() {
|
// Extract all the data from the table that we need for the charts
|
||||||
|
void WildMonChart::readTable() {
|
||||||
|
clearTableData();
|
||||||
if (!this->table)
|
if (!this->table)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
setWindowTitle(QString("Wild Pokémon Summary -- %1").arg(this->table->encounterField().name));
|
setWindowTitle(QString("%1 - %2").arg(baseWindowTitle).arg(this->table->encounterField().name));
|
||||||
|
|
||||||
// Read data about encounter groups, e.g. for "fishing_mons" we want to know indexes 2-4 belong to good_rod (group index 1).
|
// Read data about encounter groups, e.g. for "fishing_mons" we want to know table indexes 2-4 belong to "good_rod"
|
||||||
// Each group will be represented as a separate bar on the graph.
|
|
||||||
QList<QString> groupNames;
|
|
||||||
QMap<int, int> tableIndexToGroupIndex;
|
|
||||||
int groupIndex = 0;
|
|
||||||
for (auto groupPair : this->table->encounterField().groups) {
|
for (auto groupPair : this->table->encounterField().groups) {
|
||||||
groupNames.prepend(groupPair.first);
|
// Prepending names here instead of appending so that charts can match the order in the table visually.
|
||||||
for (auto i : groupPair.second) {
|
this->groupNames.prepend(groupPair.first);
|
||||||
tableIndexToGroupIndex.insert(i, groupIndex);
|
for (auto i : groupPair.second)
|
||||||
}
|
this->tableIndexToGroupName.insert(i, groupPair.first);
|
||||||
groupIndex++;
|
|
||||||
}
|
}
|
||||||
const int numGroups = qMax(1, groupNames.length()); // Implicitly 1 group when none are listed
|
if (this->groupNames.isEmpty())
|
||||||
|
this->groupNames.append(QString()); // Implicitly 1 unnamed group when none are listed
|
||||||
|
|
||||||
// Read data from the table, combining data for duplicate species entries
|
// Read data from the table, combining data for duplicate entries
|
||||||
const QList<double> tableValues = this->table->percentages();
|
const QList<double> tableFrequencies = this->table->percentages();
|
||||||
const QVector<WildPokemon> tablePokemon = this->table->encounterData().wildPokemon;
|
const QVector<WildPokemon> tablePokemon = this->table->encounterData().wildPokemon;
|
||||||
QMap<QString, ChartData> speciesToChartData;
|
const int numRows = qMin(tableFrequencies.length(), tablePokemon.length());
|
||||||
for (int i = 0; i < qMin(tableValues.length(), tablePokemon.length()); i++) {
|
|
||||||
const double value = tableValues.at(i);
|
|
||||||
const WildPokemon pokemon = tablePokemon.at(i);
|
|
||||||
groupIndex = tableIndexToGroupIndex.value(i, 0);
|
|
||||||
|
|
||||||
if (speciesToChartData.contains(pokemon.species)) {
|
|
||||||
// Duplicate species entry
|
|
||||||
ChartData *entry = &speciesToChartData[pokemon.species];
|
|
||||||
entry->values[groupIndex] += value;
|
|
||||||
if (entry->minLevel > pokemon.minLevel)
|
|
||||||
entry->minLevel = pokemon.minLevel;
|
|
||||||
if (entry->maxLevel < pokemon.maxLevel)
|
|
||||||
entry->maxLevel = pokemon.maxLevel;
|
|
||||||
} else {
|
|
||||||
// New species entry
|
|
||||||
ChartData entry;
|
|
||||||
entry.minLevel = pokemon.minLevel;
|
|
||||||
entry.maxLevel = pokemon.maxLevel;
|
|
||||||
entry.values.insert(groupIndex, value);
|
|
||||||
speciesToChartData.insert(pokemon.species, entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate chart
|
|
||||||
QList<QBarSet*> barSets;
|
|
||||||
const QString speciesPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_species_prefix);
|
const QString speciesPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_species_prefix);
|
||||||
for (auto mapPair = speciesToChartData.cbegin(), end = speciesToChartData.cend(); mapPair != end; mapPair++) {
|
for (int i = 0; i < numRows; i++) {
|
||||||
const ChartData entry = mapPair.value();
|
const double frequency = tableFrequencies.at(i);
|
||||||
|
const WildPokemon pokemon = tablePokemon.at(i);
|
||||||
|
const QString groupName = this->tableIndexToGroupName.value(i);
|
||||||
|
|
||||||
// Strip 'SPECIES_' prefix
|
// Create species label (strip 'SPECIES_' prefix).
|
||||||
QString label = mapPair.key();
|
QString label = pokemon.species;
|
||||||
if (label.startsWith(speciesPrefix))
|
if (label.startsWith(speciesPrefix))
|
||||||
label.remove(0, speciesPrefix.length());
|
label.remove(0, speciesPrefix.length());
|
||||||
|
|
||||||
// Add level range to label
|
// Add species/level frequency data
|
||||||
if (showLevelRange) {
|
Summary *summary = &this->speciesToGroupedData[label][groupName];
|
||||||
if (entry.minLevel == entry.maxLevel)
|
summary->speciesFrequency += frequency;
|
||||||
label.append(QString(" (Lv %1)").arg(entry.minLevel));
|
if (pokemon.minLevel > pokemon.maxLevel)
|
||||||
else
|
continue; // Invalid
|
||||||
label.append(QString(" (Lv %1-%2)").arg(entry.minLevel).arg(entry.maxLevel));
|
int numLevels = pokemon.maxLevel - pokemon.minLevel + 1;
|
||||||
}
|
for (int level = pokemon.minLevel; level <= pokemon.maxLevel; level++)
|
||||||
|
summary->levelFrequencies[level] += frequency / numLevels;
|
||||||
|
|
||||||
auto set = new QBarSet(label);
|
if (this->tableMinLevel > pokemon.minLevel)
|
||||||
|
this->tableMinLevel = pokemon.minLevel;
|
||||||
|
if (this->tableMaxLevel < pokemon.maxLevel)
|
||||||
|
this->tableMaxLevel = pokemon.maxLevel;
|
||||||
|
}
|
||||||
|
|
||||||
// Add encounter chance data (in reverse order, to match the table's group order visually)
|
// Populate combo boxes
|
||||||
for (int i = numGroups - 1; i >= 0; i--)
|
const QSignalBlocker blocker1(ui->comboBox_Species);
|
||||||
set->append(entry.values.value(i, 0));
|
const QSignalBlocker blocker2(ui->comboBox_Group);
|
||||||
|
ui->comboBox_Species->clear();
|
||||||
|
ui->comboBox_Species->addItems(getSpeciesNames());
|
||||||
|
ui->comboBox_Group->clear();
|
||||||
|
if (usesGroupLabels()) {
|
||||||
|
ui->comboBox_Group->addItems(this->groupNames);
|
||||||
|
ui->comboBox_Group->setEnabled(true);
|
||||||
|
} else {
|
||||||
|
ui->comboBox_Group->setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Insert bar set. We order them from lowest to highest total, left-to-right.
|
void WildMonChart::createCharts() {
|
||||||
int i = 0;
|
createSpeciesDistributionChart();
|
||||||
for (; i < barSets.length(); i++){
|
createLevelDistributionChart();
|
||||||
if (barSets.at(i)->sum() > set->sum())
|
|
||||||
|
// Turn off the animation once it's played, otherwise it replays any time the window changes size.
|
||||||
|
// TODO: Store timer, disable if closing or creating new chart
|
||||||
|
//QTimer::singleShot(chart->animationDuration() + 500, this, &WildMonChart::stopChartAnimation);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList WildMonChart::getSpeciesNames() const {
|
||||||
|
return this->speciesToGroupedData.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
double WildMonChart::getSpeciesFrequency(const QString &species, const QString &groupName) const {
|
||||||
|
return this->speciesToGroupedData[species][groupName].speciesFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<int, double> WildMonChart::getLevelFrequencies(const QString &species, const QString &groupName) const {
|
||||||
|
return this->speciesToGroupedData[species][groupName].levelFrequencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WildMonChart::usesGroupLabels() const {
|
||||||
|
return this->groupNames.length() > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WildMonChart::createSpeciesDistributionChart() {
|
||||||
|
QList<QBarSet*> barSets;
|
||||||
|
for (const auto species : getSpeciesNames()) {
|
||||||
|
// Add encounter chance data
|
||||||
|
auto set = new QBarSet(species);
|
||||||
|
for (auto groupName : this->groupNames)
|
||||||
|
set->append(getSpeciesFrequency(species, groupName) * 100);
|
||||||
|
|
||||||
|
// We order the bar sets from lowest to highest total, left-to-right.
|
||||||
|
for (int i = 0; i < barSets.length() + 1; i++){
|
||||||
|
if (i >= barSets.length() || barSets.at(i)->sum() > set->sum()) {
|
||||||
|
barSets.insert(i, set);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
barSets.insert(i, set);
|
|
||||||
|
// Show species name and % when hovering over a bar set. This covers some shortfalls in our ability to control the chart design
|
||||||
|
// (i.e. bar segments may be too narrow to see the % label, or colors may be hard to match to the legend).
|
||||||
|
connect(set, &QBarSet::hovered, [set, species] (bool on, int i) {
|
||||||
|
QString text = on ? QString("%1 - %2%").arg(species).arg(set->at(i)) : "";
|
||||||
|
QToolTip::showText(QCursor::pos(), text);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto series = new QHorizontalPercentBarSeries();
|
auto series = new QHorizontalPercentBarSeries();
|
||||||
series->setLabelsVisible();
|
series->setLabelsVisible();
|
||||||
//series->setLabelsPrecision(x); // This appears to have no effect for any value 'x'? Ideally we'd display 1-2 decimal places
|
|
||||||
series->append(barSets);
|
series->append(barSets);
|
||||||
|
|
||||||
auto chart = new QChart();
|
auto chart = new QChart();
|
||||||
|
@ -135,29 +173,93 @@ void WildMonChart::updateChart() {
|
||||||
|
|
||||||
// X-axis is the values (percentages). We're already showing percentages on the bar, so we just display 0/50/100%
|
// X-axis is the values (percentages). We're already showing percentages on the bar, so we just display 0/50/100%
|
||||||
auto axisX = new QValueAxis();
|
auto axisX = new QValueAxis();
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
|
axisX->setLabelFormat("%u%%");
|
||||||
// Not critical, but the percentage ticks on the x-axis have no need for decimals.
|
|
||||||
// This property doesn't exist prior to Qt 6.7
|
|
||||||
axisX->setLabelDecimals(0);
|
|
||||||
#endif
|
|
||||||
axisX->setTickCount(3);
|
axisX->setTickCount(3);
|
||||||
chart->addAxis(axisX, Qt::AlignBottom);
|
chart->addAxis(axisX, Qt::AlignBottom);
|
||||||
series->attachAxis(axisX);
|
series->attachAxis(axisX);
|
||||||
|
|
||||||
// Y-axis is the names of encounter groups (e.g. Old Rod, Good Rod...)
|
// Y-axis is the names of encounter groups (e.g. Old Rod, Good Rod...)
|
||||||
if (numGroups > 1) {
|
if (usesGroupLabels()) {
|
||||||
auto axisY = new QBarCategoryAxis();
|
auto axisY = new QBarCategoryAxis();
|
||||||
axisY->setCategories(groupNames);
|
axisY->setCategories(this->groupNames);
|
||||||
chart->addAxis(axisY, Qt::AlignLeft);
|
chart->addAxis(axisY, Qt::AlignLeft);
|
||||||
series->attachAxis(axisY);
|
series->attachAxis(axisY);
|
||||||
|
} else {
|
||||||
|
// TODO: y-axis has weird labels for a few frames on opening
|
||||||
}
|
}
|
||||||
|
|
||||||
delete ui->chartView->chart();
|
// TODO: Delete old chart
|
||||||
ui->chartView->setChart(chart);
|
ui->chartView_SpeciesDistribution->setChart(chart);
|
||||||
|
}
|
||||||
// Turn off the animation once it's played, otherwise it replays any time the window changes size.
|
|
||||||
QTimer::singleShot(chart->animationDuration() + 500, [this] {
|
void WildMonChart::createLevelDistributionChart() {
|
||||||
if (ui->chartView->chart())
|
// TODO: Handle combined chart
|
||||||
ui->chartView->chart()->setAnimationOptions(QChart::NoAnimation);
|
const QString species = ui->comboBox_Species->currentText();
|
||||||
});
|
const QString groupName = ui->comboBox_Group->currentText();
|
||||||
|
|
||||||
|
const double speciesFrequency = getSpeciesFrequency(species, groupName);
|
||||||
|
const QMap<int, double> levelFrequencies = getLevelFrequencies(species, groupName);
|
||||||
|
const QList<int> levels = levelFrequencies.keys();
|
||||||
|
|
||||||
|
int minLevel = !levels.isEmpty() ? levels.first() : 0;
|
||||||
|
int maxLevel = !levels.isEmpty() ? levels.last() : 0;
|
||||||
|
if (maxLevel < minLevel)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double maxPercent = 0.0;
|
||||||
|
QStringList categories;
|
||||||
|
auto set = new QBarSet(species);
|
||||||
|
for (int i = minLevel; i <= maxLevel; i++) {
|
||||||
|
double percent = (levelFrequencies.value(i, 0) / speciesFrequency) * 100;
|
||||||
|
if (maxPercent < percent)
|
||||||
|
maxPercent = percent;
|
||||||
|
set->append(percent);
|
||||||
|
categories.append(QString::number(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show level and % when hovering over a bar set. This covers some shortfalls in our ability to control the chart design.
|
||||||
|
connect(set, &QBarSet::hovered, [set, categories] (bool on, int i) {
|
||||||
|
QString text = on ? QString("Lv%1 - %2%").arg(categories.at(i)).arg(set->at(i)) : "";
|
||||||
|
QToolTip::showText(QCursor::pos(), text);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto series = new QBarSeries();
|
||||||
|
series->append(set);
|
||||||
|
//series->setLabelsVisible();
|
||||||
|
|
||||||
|
auto chart = new QChart();
|
||||||
|
chart->addSeries(series);
|
||||||
|
//chart->setTitle("");
|
||||||
|
chart->setAnimationOptions(QChart::SeriesAnimations);
|
||||||
|
chart->legend()->setVisible(true);
|
||||||
|
chart->legend()->setShowToolTips(true);
|
||||||
|
chart->legend()->setAlignment(Qt::AlignBottom);
|
||||||
|
|
||||||
|
QBarCategoryAxis *axisX = new QBarCategoryAxis();
|
||||||
|
axisX->append(categories);
|
||||||
|
chart->addAxis(axisX, Qt::AlignBottom);
|
||||||
|
series->attachAxis(axisX);
|
||||||
|
|
||||||
|
auto roundUp = [](int num, int multiple) {
|
||||||
|
auto remainder = num % multiple;
|
||||||
|
if (remainder == 0)
|
||||||
|
return num;
|
||||||
|
return num + multiple - remainder;
|
||||||
|
};
|
||||||
|
|
||||||
|
QValueAxis *axisY = new QValueAxis();
|
||||||
|
axisY->setMax(roundUp(qCeil(maxPercent), 5));
|
||||||
|
//axisY->setTickType(QValueAxis::TicksDynamic);
|
||||||
|
//axisY->setTickInterval(5);
|
||||||
|
axisY->setLabelFormat("%u%%");
|
||||||
|
chart->addAxis(axisY, Qt::AlignLeft);
|
||||||
|
series->attachAxis(axisY);
|
||||||
|
|
||||||
|
// TODO: Cache old chart
|
||||||
|
ui->chartView_LevelDistribution->setChart(chart);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WildMonChart::stopChartAnimation() {
|
||||||
|
if (ui->chartView_SpeciesDistribution->chart())
|
||||||
|
ui->chartView_SpeciesDistribution->chart()->setAnimationOptions(QChart::NoAnimation);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue