diff --git a/CHANGELOG.md b/CHANGELOG.md index c352dc9dc..47944f0fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ ### Added +- Add new sorting strategy: 'byLabel'. - Add spacing property for plot axis style structure. ### Changed diff --git a/src/apps/weblib/typeschema-api/config.yaml b/src/apps/weblib/typeschema-api/config.yaml index 807e83cf5..0ba5df68d 100644 --- a/src/apps/weblib/typeschema-api/config.yaml +++ b/src/apps/weblib/typeschema-api/config.yaml @@ -114,8 +114,11 @@ definitions: appear in the data set. - 'byValue': markers will be sorted by the corresponding measure (if present) in decreasing order. + - 'byLabel': markers will be sorted by the corresponding shown categories + (if present) in natural order (ASCII case-insensitive, space-insensitive + alphabetical order and numbers are compared by value). type: string - enum: [none, byValue] + enum: [none, byValue, byLabel] reverse: description: Reverts the order of the markers if set. type: boolean diff --git a/src/chart/generator/plotbuilder.cpp b/src/chart/generator/plotbuilder.cpp index f8fd01901..c00bdfd64 100644 --- a/src/chart/generator/plotbuilder.cpp +++ b/src/chart/generator/plotbuilder.cpp @@ -18,6 +18,7 @@ #include "base/math/floating.h" #include "base/math/range.h" #include "base/refl/auto_enum.h" +#include "base/text/naturalcmp.h" #include "chart/main/style.h" #include "chart/options/align.h" #include "chart/options/channel.h" @@ -135,19 +136,40 @@ std::vector PlotBuilder::sortedBuckets( {}, &BucketInfo::index); if (it == sorted.end() || it->index != idx.itemId) - it = sorted.emplace(it, idx.itemId, 0.0); + it = sorted.emplace(it, + idx.itemId, + 0.0, + (marker.*buckets.marker_id_get).label + ? &(marker.*buckets.marker_id_get) + .label->value + : nullptr); it->size += marker.size.getCoord( !plot->getOptions()->getOrientation()); } - if (plot->getOptions()->getChannels().axisPropsAt(axisIndex).sort - == Sort::byValue) + switch (plot->getOptions() + ->getChannels() + .axisPropsAt(axisIndex) + .sort) { + case Sort::byValue: std::ranges::stable_sort(sorted, [](const BucketInfo &lhs, const BucketInfo &rhs) { return Math::Floating::less(lhs.size, rhs.size); }); + break; + case Sort::byLabel: + std::ranges::stable_sort(sorted, + [](const BucketInfo &lhs, const BucketInfo &rhs) + { + if (rhs.label == nullptr || lhs.label == nullptr) + return lhs.label != nullptr; + return Text::NaturalCmp{}(*lhs.label, *rhs.label); + }); + break; + default: break; + } if (plot->getOptions() ->getChannels() @@ -440,10 +462,10 @@ void PlotBuilder::calcAxis(const Data::DataTable &dataTable, } else { for (auto merge = - plot->getOptions()->dimLabelIndex(+type) == 0 - && (type != plot->getOptions()->mainAxisType() - || axisProps.sort != Sort::byValue - || scale.dimensions().size() == 1); + axisProps.sort == Sort::byLabel + || (plot->getOptions()->dimLabelIndex(+type) == 0 + && (axisProps.sort == Sort::none + || scale.dimensions().size() == 1)); const auto &marker : plot->markers) { if (!marker.enabled) continue; diff --git a/src/chart/generator/plotbuilder.h b/src/chart/generator/plotbuilder.h index d25470425..15a6a924d 100644 --- a/src/chart/generator/plotbuilder.h +++ b/src/chart/generator/plotbuilder.h @@ -31,6 +31,7 @@ class PlotBuilder { std::size_t index{}; double size{}; + const std::string *label{}; }; void initDimensionTrackers(); diff --git a/src/chart/options/sort.h b/src/chart/options/sort.h index ebcd47056..57410a360 100644 --- a/src/chart/options/sort.h +++ b/src/chart/options/sort.h @@ -6,7 +6,7 @@ namespace Vizzu::Gen { -enum class Sort : std::uint8_t { none, byValue }; +enum class Sort : std::uint8_t { none, byValue, byLabel }; } diff --git a/test/e2e/tests/fixes.json b/test/e2e/tests/fixes.json index 90a3ab56d..80b24f4a4 100644 --- a/test/e2e/tests/fixes.json +++ b/test/e2e/tests/fixes.json @@ -29,7 +29,7 @@ "refs": ["00f01d9"] }, "319": { - "refs": ["7991f1b"] + "refs": ["f237567"] }, "320": { "refs": ["e4b8a2f"] diff --git a/test/e2e/tests/fixes/319.mjs b/test/e2e/tests/fixes/319.mjs index 3ba947e21..552784f93 100644 --- a/test/e2e/tests/fixes/319.mjs +++ b/test/e2e/tests/fixes/319.mjs @@ -5,11 +5,11 @@ const testSteps = [ series: [ { name: 'Foo', - values: ['Alice', 'Bob', 'Ted', 'Alice', 'Bob', 'Ted', 'Alice'] + values: ['Ted', 'Alice', 'Bob', 'Ted', 'Alice', 'Bob', 'Ted'] }, { name: 'Foo2', values: ['A', 'A', 'A', 'B', 'B', 'B', 'A'] }, { name: 'Foo3', values: ['X', 'Y', 'Z', 'X', 'Y', 'Z', 'Y'] }, - { name: 'Bar', values: [15, 32, 12, 23, 41, 31, 1] } + { name: 'Bar', values: [23, 32, 12, 15, 41, 31, 1] } ] } }), @@ -30,7 +30,8 @@ const testSteps = [ }), (chart) => chart.animate({ - x: { sort: 'none' } + x: { set: ['Foo2', 'Foo'], labelLevel: 1, sort: 'byLabel' }, + y: { reverse: true } }) ] diff --git a/tools/ci/type/gen-presets.cjs b/tools/ci/type/gen-presets.cjs index 4b24b5cd4..ae3bab1ab 100644 --- a/tools/ci/type/gen-presets.cjs +++ b/tools/ci/type/gen-presets.cjs @@ -100,7 +100,7 @@ function genSchema(presets) { }, sort: { type: 'string', - enum: ['none', 'byValue'] + enum: ['none', 'byValue', 'byLabel'] } } }