diff --git a/stats/statsaxis.cpp b/stats/statsaxis.cpp index 8b8694964..d31b5827b 100644 --- a/stats/statsaxis.cpp +++ b/stats/statsaxis.cpp @@ -57,6 +57,17 @@ std::pair StatsAxis::minMaxScreen() const : std::make_pair(zeroOnScreen, zeroOnScreen - size); } +std::pair StatsAxis::horizontalOverhang() const +{ + // If the labels are between ticks, they cannot peak out + if (!horizontal || labelsBetweenTicks) + return { 0.0, 0.0 }; + QFontMetrics fm(labelFont); + auto [firstLabel, lastLabel] = getFirstLastLabel(); + return { fm.size(Qt::TextSingleLine, firstLabel).width() / 2.0, + fm.size(Qt::TextSingleLine, lastLabel).width() / 2.0 }; +} + void StatsAxis::setRange(double minIn, double maxIn) { min = minIn; @@ -223,6 +234,19 @@ ValueAxis::ValueAxis(const QString &title, double min, double max, int decimals, StatsAxis(title, horizontal, false), min(min), max(max), decimals(decimals) { + // Avoid degenerate cases + if (max - min < 0.0001) { + max += 0.5; + min -= 0.5; + } +} + +// Attention: this is only heuristics. Before setting the actual size, we +// don't know the actual numbers of the minimum and maximum value. +std::pair ValueAxis::getFirstLastLabel() const +{ + QLocale loc; + return { loc.toString(min, 'f', decimals), loc.toString(max, 'f', decimals) }; } void ValueAxis::updateLabels() @@ -230,15 +254,8 @@ void ValueAxis::updateLabels() labels.clear(); ticks.clear(); - // Avoid degenerate cases - if (max - min < 0.0001) { - max += 0.5; - min -= 0.5; - } - QLocale loc; - QString minString = loc.toString(min, 'f', decimals); - QString maxString = loc.toString(max, 'f', decimals); + auto [minString, maxString] = getFirstLastLabel(); int numTicks = guessNumTicks({ minString, maxString}); // Use full decimal increments @@ -279,6 +296,14 @@ CountAxis::CountAxis(const QString &title, int count, bool horizontal) : { } +// Attention: this is only heuristics. Before setting the actual size, we +// don't know the actual numbers of the minimum and maximum value. +std::pair CountAxis::getFirstLastLabel() const +{ + QLocale loc; + return { QString("0"), loc.toString(count) }; +} + void CountAxis::updateLabels() { labels.clear(); @@ -333,6 +358,13 @@ CategoryAxis::CategoryAxis(const QString &title, const std::vector &lab setRange(-0.5, static_cast(labels.size()) + 0.5); } +// No implementation because the labels are inside ticks and this +// is only used to calculate the "overhang" of labels under ticks. +std::pair CategoryAxis::getFirstLastLabel() const +{ + return { QString(), QString() }; +} + void CategoryAxis::updateLabels() { // TODO: paint ellipses if space too small @@ -370,6 +402,14 @@ HistogramAxis::HistogramAxis(const QString &title, std::vector HistogramAxis::getFirstLastLabel() const +{ + if (bin_values.empty()) + return { QString(), QString() }; + else + return { bin_values.front().name, bin_values.back().name }; +} + // Initialize a histogram axis with the given labels. Labels are specified as (name, value, recommended) triplets. // If labels are skipped, try to skip it in such a way that a recommended label is shown. // The one example where this is relevant is the quarterly bins, which are formated as (2019, q1, q2, q3, 2020, ...). diff --git a/stats/statsaxis.h b/stats/statsaxis.h index 72a191963..9d46f753a 100644 --- a/stats/statsaxis.h +++ b/stats/statsaxis.h @@ -16,6 +16,7 @@ public: // Returns minimum and maximum of shown range, not of data points. std::pair minMax() const; std::pair minMaxScreen() const; // minimum and maximum in screen coordinates + std::pair horizontalOverhang() const; // space that labels peak out in horizontal axes double width() const; // Only supported by vertical axes. Only valid after setSize(). double height() const; // Only supported for horizontal axes. Always valid. @@ -39,6 +40,7 @@ protected: std::vector