From 1eb6d02f30f27abe9e72f3a4bb277cd924fdffda Mon Sep 17 00:00:00 2001 From: Bela Schaum Date: Sun, 17 Nov 2024 18:31:39 +0100 Subject: [PATCH 1/5] Implement separation --- CHANGELOG.md | 5 +++++ src/apps/weblib/typeschema-api/config.yaml | 14 +++++++++++-- src/chart/generator/guides.cpp | 13 +++++++----- src/chart/generator/plotbuilder.cpp | 12 +++++++---- src/chart/options/channel.cpp | 6 ------ src/chart/options/channel.h | 24 ++++++++++++++-------- src/chart/options/channels.h | 12 +++++++++++ src/chart/options/config.cpp | 19 +++++++++++++++++ src/chart/options/options.h | 4 +++- 9 files changed, 82 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cd69843e..9c1aff4cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,11 @@ - Fix Mekko charts: The main axis handled as dimension. - LabelLevel can be used to handle measure axis as dimension axis. +### Changed + +- Separate Channel properties to AxisChannel properties at config. +- Channels 'set' rewrite doesn't clear AxisChannel properties. + ## [0.15.0] - 2024-10-28 ### Fixed diff --git a/src/apps/weblib/typeschema-api/config.yaml b/src/apps/weblib/typeschema-api/config.yaml index e9eb039f8..0a793f7f1 100644 --- a/src/apps/weblib/typeschema-api/config.yaml +++ b/src/apps/weblib/typeschema-api/config.yaml @@ -76,6 +76,12 @@ definitions: oneOf: - type: number - { type: string, enum: [auto] } + + AxisChannel: + description: | + AxisChannels are special channel settings for the positional channels. + type: object + properties: axis: description: Enables the axis line on axis channels. $ref: AutoBool @@ -109,14 +115,18 @@ definitions: type: object properties: x: - $ref: Channel + allOf: + - $ref: Channel + - $ref: AxisChannel description: | Parameters for the X-axis, determining the position of the markers on the x-axis - or their angle when using polar coordinates. Note: leaving x and y channels empty will result in a chart "without coordinates" like a Treemap or a Bubble Chart. y: - $ref: Channel + allOf: + - $ref: Channel + - $ref: AxisChannel description: | Parameters for the Y-axis, determining the position of the markers on the y-axis - or their radius when using polar coordinates) . diff --git a/src/chart/generator/guides.cpp b/src/chart/generator/guides.cpp index 86f9abce3..31c5eba2c 100644 --- a/src/chart/generator/guides.cpp +++ b/src/chart/generator/guides.cpp @@ -20,9 +20,9 @@ bool GuidesByAxis::operator==(const GuidesByAxis &other) const Guides::Guides(const Options &options) { - const auto &xOpt = options.getChannels().at(AxisId::x); - const auto &yOpt = options.getChannels().at(AxisId::y); - if (xOpt.isEmpty() && yOpt.isEmpty()) return; + const auto &xChannel = options.getChannels().at(AxisId::x); + const auto &yChannel = options.getChannels().at(AxisId::y); + if (xChannel.isEmpty() && yChannel.isEmpty()) return; auto xIsMeasure = options.isMeasure(ChannelId::x); auto yIsMeasure = options.isMeasure(ChannelId::y); @@ -30,6 +30,9 @@ Guides::Guides(const Options &options) auto isCircle = options.geometry.get() == ShapeType::circle; auto isHorizontal = options.isHorizontal(); + const auto &xOpt = options.getChannels().axisPropsAt(AxisId::x); + const auto &yOpt = options.getChannels().axisPropsAt(AxisId::y); + x.axis = xOpt.axis.getValue(yIsMeasure); y.axis = yOpt.axis.getValue(xIsMeasure && !isPolar); @@ -58,7 +61,7 @@ Guides::Guides(const Options &options) x.labels = xOpt.labels.getValue( (!isPolar || yIsMeasure) && ((xIsMeasure && (x.axisSticks || x.interlacings)) - || (!xIsMeasure && !xOpt.isEmpty()))); + || (!xIsMeasure && !xChannel.isEmpty()))); auto stretchedPolar = isPolar && !yIsMeasure @@ -67,7 +70,7 @@ Guides::Guides(const Options &options) y.labels = yOpt.labels.getValue( !stretchedPolar && ((yIsMeasure && (y.axisSticks || y.interlacings)) - || (!yIsMeasure && !yOpt.isEmpty()))); + || (!yIsMeasure && !yChannel.isEmpty()))); } GuidesByAxis &Guides::at(AxisId channel) diff --git a/src/chart/generator/plotbuilder.cpp b/src/chart/generator/plotbuilder.cpp index 6f39c67d5..7803e0fe5 100644 --- a/src/chart/generator/plotbuilder.cpp +++ b/src/chart/generator/plotbuilder.cpp @@ -353,7 +353,7 @@ void PlotBuilder::calcLegendAndLabel(const Data::DataTable &dataTable) calcLegend.measure = {std::get<0>(stats.at(type)), meas->getColIndex(), dataTable.getUnit(meas->getColIndex()), - scale.step.getValue()}; + {1}}; } } else if (!scale.isEmpty()) { @@ -404,6 +404,10 @@ void PlotBuilder::calcAxis(const Data::DataTable &dataTable, const auto &scale = plot->getOptions()->getChannels().at(type); if (scale.isEmpty()) return; + auto &axisProps = + plot->getOptions()->getChannels().axisPropsAt(type); + ; + auto &axis = plot->axises.at(type); auto isAutoTitle = scale.title.isAuto(); @@ -419,12 +423,12 @@ void PlotBuilder::calcAxis(const Data::DataTable &dataTable, axis.measure = {Math::Range<>::Raw(0, 100), meas.getColIndex(), "%", - scale.step.getValue()}; + axisProps.step.getValue()}; else axis.measure = {std::get<0>(stats.at(type)), meas.getColIndex(), dataTable.getUnit(meas.getColIndex()), - scale.step.getValue()}; + axisProps.step.getValue()}; } else { for (auto merge = @@ -449,7 +453,7 @@ void PlotBuilder::calcAxis(const Data::DataTable &dataTable, merge); } if (auto &&series = plot->getOptions()->labelSeries(type); - !axis.dimension.setLabels(scale.step.getValue(1.0)) + !axis.dimension.setLabels(axisProps.step.getValue(1.0)) && series && isAutoTitle) axis.title = series.value().getColIndex(); } diff --git a/src/chart/options/channel.cpp b/src/chart/options/channel.cpp index d8ce2c021..099c96b64 100644 --- a/src/chart/options/channel.cpp +++ b/src/chart/options/channel.cpp @@ -151,12 +151,6 @@ void Channel::reset() set = {}; labelLevel = {}; title = {}; - axis = Base::AutoBool(); - labels = Base::AutoBool(); - ticks = Base::AutoBool(); - guides = Base::AutoBool(); - markerGuides = Base::AutoBool(); - interlacing = Base::AutoBool(); } bool Channel::isEmpty() const diff --git a/src/chart/options/channel.h b/src/chart/options/channel.h index 944f7b8be..032508795 100644 --- a/src/chart/options/channel.h +++ b/src/chart/options/channel.h @@ -118,9 +118,22 @@ struct ChannelSeriesList bool removeSeries(const Data::SeriesIndex &index); }; -class Channel +struct AxisChannelProperties +{ + Base::AutoBool axis{}; + Base::AutoBool labels{}; + Base::AutoBool ticks{}; + Base::AutoBool interlacing{}; + Base::AutoBool guides{}; + Base::AutoBool markerGuides{}; + Base::AutoParam step{}; + + [[nodiscard]] bool operator==( + const AxisChannelProperties &) const = default; +}; + +struct Channel { -public: using OptionalIndex = ChannelSeriesList::OptionalIndex; using IndexSet = std::set; using DimensionIndices = ChannelSeriesList::DimensionIndices; @@ -161,13 +174,6 @@ class Channel ChannelRange range{}; Base::AutoParam labelLevel{}; Base::AutoParam title{}; - Base::AutoBool axis{}; - Base::AutoBool labels{}; - Base::AutoBool ticks{}; - Base::AutoBool guides{}; - Base::AutoBool markerGuides{}; - Base::AutoBool interlacing{}; - Base::AutoParam step{}; }; [[nodiscard]] constexpr ChannelId operator-(const AxisId &axis) diff --git a/src/chart/options/channels.h b/src/chart/options/channels.h index 9b1c477f4..d31d45f93 100644 --- a/src/chart/options/channels.h +++ b/src/chart/options/channels.h @@ -15,6 +15,7 @@ namespace Vizzu::Gen struct Channels : Refl::EnumArray { using IndexSet = std::set; + EnumArray axisProps; [[nodiscard]] bool anyAxisSet() const; [[nodiscard]] bool isEmpty() const; @@ -37,6 +38,17 @@ struct Channels : Refl::EnumArray return at(-id); } + [[nodiscard]] const AxisChannelProperties &axisPropsAt( + const AxisId &id) const + { + return axisProps[id]; + } + + [[nodiscard]] AxisChannelProperties &axisPropsAt(const AxisId &id) + { + return axisProps[id]; + } + void removeSeries(const Data::SeriesIndex &index); [[nodiscard]] bool isSeriesUsed( diff --git a/src/chart/options/config.cpp b/src/chart/options/config.cpp index d4bdd8897..a798a3422 100644 --- a/src/chart/options/config.cpp +++ b/src/chart/options/config.cpp @@ -33,6 +33,12 @@ std::string Config::paramsJson() for (const auto ¶m : channelParams) arr << "channels." + std::string{channelName} + "." + std::string{param}; + + if (channelName == "x" || channelName == "y") + for (const auto ¶m : + getAccessorNames()) + arr << "channels." + std::string{channelName} + "." + + std::string{param}; } return res; } @@ -112,6 +118,14 @@ void Config::setChannelParam(const std::string &path, if (auto &&accessor = getAccessor(property).set) accessor(channel, value); + else if (auto &&axisAccessor = + getAccessor(property).set; + (channelId == AxisId::x || channelId == AxisId::y) + && axisAccessor) + axisAccessor( + options.getChannels().axisPropsAt( + channelId == AxisId::x ? AxisId::x : AxisId::y), + value); else throw std::logic_error( path + "/" + value @@ -130,6 +144,11 @@ std::string Config::getChannelParam(const std::string &path) const if (auto &&accessor = getAccessor(property).get) return accessor(channel); + if (auto &&axisAccessor = + getAccessor(property).get; + (id == AxisId::x || id == AxisId::y) && axisAccessor) + return axisAccessor(options.get().getChannels().axisPropsAt( + id == AxisId::x ? AxisId::x : AxisId::y)); throw std::logic_error(path + ": invalid channel parameter"); } diff --git a/src/chart/options/options.h b/src/chart/options/options.h index 9ae579a6f..df867a263 100644 --- a/src/chart/options/options.h +++ b/src/chart/options/options.h @@ -207,7 +207,9 @@ class Options : public OptionProperties [](std::index_sequence) { return decltype(channels){ - Channel::makeChannel(static_cast(Ix))...}; + {{Channel::makeChannel( + static_cast(Ix))...}}, + {}}; }(std::make_index_sequence< std::tuple_size_v>{})}; From 3514412ddea34156224220f12850e0cf39d610c8 Mon Sep 17 00:00:00 2001 From: Bela Schaum Date: Mon, 18 Nov 2024 12:41:34 +0100 Subject: [PATCH 2/5] Reset means reset + set doesn't reset --- src/chart/options/channel.cpp | 1 + src/chart/options/config.cpp | 16 ++++++---------- .../tests/config_tests/dimension_axis_title.mjs | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/chart/options/channel.cpp b/src/chart/options/channel.cpp index 099c96b64..2800d0183 100644 --- a/src/chart/options/channel.cpp +++ b/src/chart/options/channel.cpp @@ -151,6 +151,7 @@ void Channel::reset() set = {}; labelLevel = {}; title = {}; + range = {}; } bool Channel::isEmpty() const diff --git a/src/chart/options/config.cpp b/src/chart/options/config.cpp index a798a3422..34606b9fa 100644 --- a/src/chart/options/config.cpp +++ b/src/chart/options/config.cpp @@ -89,29 +89,25 @@ void Config::setChannelParam(const std::string &path, if (property == "set") { if (parts.size() == 3) { - channel.reset(); + channel.set = {}; options.markersInfo.clear(); return; } - if (auto &listParser = ChannelSeriesList::Parser::instance(); - parts.size() == 4) { + auto &listParser = ChannelSeriesList::Parser::instance(); + if (parts.size() == 4) { if (parts[3] == "begin") { - if (parts[2] == "set") channel.reset(); - + if (parts[2] == "set") channel.set = {}; options.markersInfo.clear(); listParser.table = &table.get(); listParser.channels.resize(std::stoull(value)); return; } - listParser.current = std::nullopt; - listParser.path = parts; } - else { + else listParser.current = std::stoull(parts.at(3)); - listParser.path = parts; - } + listParser.path = parts; } if (property == "range") property += "." + parts.at(3); diff --git a/test/e2e/tests/config_tests/dimension_axis_title.mjs b/test/e2e/tests/config_tests/dimension_axis_title.mjs index 854438e75..05da009fb 100644 --- a/test/e2e/tests/config_tests/dimension_axis_title.mjs +++ b/test/e2e/tests/config_tests/dimension_axis_title.mjs @@ -26,7 +26,7 @@ const testSteps = [ (chart) => chart.animate({ x: { set: 'Baz' }, - size: { set: 'Baz' } + size: { set: 'Baz', title: 'Bigness' } }) ] From 13d675bb9c7c56ef92abde3bc695ad8db0cc8972 Mon Sep 17 00:00:00 2001 From: Bela Schaum Date: Mon, 18 Nov 2024 13:22:29 +0100 Subject: [PATCH 3/5] Fix test --- test/e2e/tests/config_tests/dimension_axis_title.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/tests/config_tests/dimension_axis_title.mjs b/test/e2e/tests/config_tests/dimension_axis_title.mjs index 05da009fb..6cd96ddbd 100644 --- a/test/e2e/tests/config_tests/dimension_axis_title.mjs +++ b/test/e2e/tests/config_tests/dimension_axis_title.mjs @@ -25,7 +25,7 @@ const testSteps = [ }), (chart) => chart.animate({ - x: { set: 'Baz' }, + x: { set: 'Baz', title: 'Who' }, size: { set: 'Baz', title: 'Bigness' } }) ] From ac76d527180c77ae20b653beb456b0892b56e5b1 Mon Sep 17 00:00:00 2001 From: Bela Schaum Date: Mon, 25 Nov 2024 18:52:30 +0100 Subject: [PATCH 4/5] fix review --- src/chart/generator/plotbuilder.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/chart/generator/plotbuilder.cpp b/src/chart/generator/plotbuilder.cpp index c5e70713b..b003a4884 100644 --- a/src/chart/generator/plotbuilder.cpp +++ b/src/chart/generator/plotbuilder.cpp @@ -406,7 +406,6 @@ void PlotBuilder::calcAxis(const Data::DataTable &dataTable, auto &axisProps = plot->getOptions()->getChannels().axisPropsAt(type); - ; auto &axis = plot->axises.at(type); From c4173b0d6133ab7109222fac1bc9ac2275a3cff8 Mon Sep 17 00:00:00 2001 From: Bela Schaum Date: Mon, 25 Nov 2024 20:19:42 +0100 Subject: [PATCH 5/5] fix axis title --- test/e2e/tests/config_tests.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/tests/config_tests.json b/test/e2e/tests/config_tests.json index fb9ce6e62..fa1b69472 100644 --- a/test/e2e/tests/config_tests.json +++ b/test/e2e/tests/config_tests.json @@ -41,7 +41,7 @@ "refs": ["2ac83c5"] }, "dimension_axis_title": { - "refs": ["33278a6"] + "refs": ["0f4b203"] }, "dimension_axis_density": { "refs": ["0de86a3"]