Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dimension axis label density #469

Merged
merged 4 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@

- Json serializer control character escape fixed. Some unicode characters
were not escaped properly.
- Fix dimension label transition on axis and legend.

### Added

- Added optional `categories` member to the `legend-marker`, `legend-label` and `plot-axis-label` events.
- Remove unused marker selection and selected marker coloring.
- Remove cursor modification over logo
- Remove cursor modification over logo.
- Make `channel.step` option to work on dimensions.

## [0.9.3] - 2023-12-20

Expand Down
48 changes: 29 additions & 19 deletions src/chart/generator/axis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,26 @@ bool DimensionAxis::operator==(const DimensionAxis &other) const
}

void DimensionAxis::setLabels(const Data::DataCube &data,
const Data::DataTable &table)
const Data::DataTable &table,
double step)
{
Values::iterator it;
for (it = values.begin(); it != values.end(); ++it) {
step = std::max(step, 1.0);
double currStep = 0.0;

for (int curr{}; auto &[slice, item] : values) {
auto colIndex =
data.getSeriesByDim(it->first.dimIndex).getColIndex();
data.getSeriesByDim(slice.dimIndex).getColIndex();
const auto &categories =
table.getInfo(colIndex.value()).categories();
if (it->first.index < categories.size())
it->second.label = categories[it->first.index];

if (slice.index < categories.size())
item.categoryValue = categories[slice.index];
else
it->second.label = "NA";
item.categoryValue = "NA";

if (++curr <= currStep) continue;
currStep += step;
item.label = item.categoryValue;
}
}

Expand All @@ -115,45 +123,47 @@ DimensionAxis interpolate(const DimensionAxis &op0,
{
DimensionAxis res;

DimensionAxis::Values::const_iterator it;
for (it = op0.values.cbegin(); it != op0.values.cend(); ++it) {
for (const auto &[slice, item] : op0.values) {
res.enabled = true;
res.values.emplace(std::piecewise_construct,
std::tuple{it->first},
std::tuple{it->second, true, 1 - factor});
std::tuple{slice},
std::forward_as_tuple(item, true, 1 - factor));
}

for (it = op1.values.cbegin(); it != op1.values.cend(); ++it) {
for (const auto &[slice, item] : op1.values) {
res.enabled = true;
auto [resIt, end] = res.values.equal_range(it->first);
auto [resIt, end] = res.values.equal_range(slice);

while (resIt != end && resIt->second.end) { ++resIt; }

if (resIt == end) {
res.values.emplace_hint(resIt,
std::piecewise_construct,
std::tuple{it->first},
std::tuple{it->second, false, factor});
std::tuple{slice},
std::forward_as_tuple(item, false, factor));
}
else {
resIt->second.end = true;

resIt->second.range =
Math::interpolate(resIt->second.range,
it->second.range,
item.range,
factor);

resIt->second.colorBase =
interpolate(resIt->second.colorBase,
it->second.colorBase,
item.colorBase,
factor);

resIt->second.label =
interpolate(resIt->second.label, item.label, factor);

resIt->second.value =
Math::interpolate(resIt->second.value,
it->second.value,
item.value,
factor);

resIt->second.weight += it->second.weight * factor;
resIt->second.weight += item.weight * factor;
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/chart/generator/axis.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ struct DimensionAxis
Math::Range<double> range;
double value;
::Anim::Interpolated<ColorBase> colorBase;
std::string label;
::Anim::Interpolated<std::string> label;
std::string categoryValue;
double weight;

Item(Math::Range<double> range,
Expand All @@ -119,6 +120,7 @@ struct DimensionAxis
value(item.value),
colorBase(item.colorBase),
label(item.label),
categoryValue(item.categoryValue),
weight(item.weight * factor)
{}

Expand Down Expand Up @@ -156,7 +158,8 @@ struct DimensionAxis
return values.cend();
}
void setLabels(const Data::DataCube &data,
const Data::DataTable &table);
const Data::DataTable &table,
double step);

private:
Values values;
Expand Down
7 changes: 5 additions & 2 deletions src/chart/generator/plot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,8 @@ void Plot::calcDimensionAxis(ChannelId type,

auto dim = scale.labelLevel;

if (type == ChannelId::x || type == ChannelId::y) {
auto &&isTypeAxis = isAxis(type);
if (isTypeAxis) {
for (const auto &marker : markers) {
const auto &id =
(type == ChannelId::x) == options->isHorizontal()
Expand Down Expand Up @@ -386,7 +387,9 @@ void Plot::calcDimensionAxis(ChannelId type,
}
}
}
axis.setLabels(dataCube, table);
axis.setLabels(dataCube,
table,
isTypeAxis ? scale.step.getValue(1.0) : 1.0);

if (auto &&series = scale.labelSeries())
axis.category = series.value().toString(table);
Expand Down
42 changes: 32 additions & 10 deletions src/chart/rendering/drawaxes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ void DrawAxes::drawDimensionLabel(bool horizontal,
ident = Geom::Point::Ident(horizontal),
normal = Geom::Point::Ident(!horizontal),
&text = it->second.label,
&categoryVal = it->second.categoryValue,
textColor = *labelStyle.color,
&weight,
&category](int index, const auto &position)
Expand Down Expand Up @@ -326,16 +327,37 @@ void DrawAxes::drawDimensionLabel(bool horizontal,

posDir = posDir.extend(sign);

OrientedLabel::create(canvas, text, posDir, labelStyle, 0)
.draw(canvas,
renderedChart,
textColor * weight * position.weight,
*labelStyle.backgroundColor,
*rootEvents.draw.plot.axis.label,
Events::Targets::axisLabel(category,
text,
text,
horizontal));
auto draw = [&](const ::Anim::Weighted<std::string> &str,
double plusWeight = 1.0)
{
OrientedLabel::create(canvas,
str.value,
posDir,
labelStyle,
0)
.draw(canvas,
renderedChart,
textColor * weight * str.weight * plusWeight,
*labelStyle.backgroundColor,
*rootEvents.draw.plot.axis.label,
Events::Targets::axisLabel(category,
categoryVal,
str.value,
horizontal));
};

if (labelStyle.position->interpolates()
&& text.interpolates())
draw(text.get(index), position.weight);
if (!labelStyle.position->interpolates()
&& !text.interpolates())
draw(text.get(0));
else if (labelStyle.position->interpolates())
draw(text.get(0), position.weight);
else if (text.interpolates()) {
draw(text.get(0));
draw(text.get(1));
}
});
}

Expand Down
28 changes: 17 additions & 11 deletions src/chart/rendering/drawlegend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,26 @@ void DrawLegend::drawDimension(const Info &info) const
auto alpha = value.second.weight * info.weight;

drawMarker(info,
value.second.label,
value.second.categoryValue,
colorBuilder.render(value.second.colorBase) * alpha,
getMarkerRect(info, itemRect));

label.draw(info.canvas,
getLabelRect(info, itemRect),
value.second.label,
style.label,
*events.label,
Events::Targets::legendLabel(info.dimension.category,
value.second.label,
value.second.label,
info.type),
DrawLabel::Options(true, alpha));
value.second.label.visit(
[&](int, auto &weighted)
{
label.draw(info.canvas,
getLabelRect(info, itemRect),
weighted.value,
style.label,
*events.label,
Events::Targets::legendLabel(
info.dimension.category,
value.second.categoryValue,
weighted.value,
info.type),
DrawLabel::Options(true,
alpha * weighted.weight));
});
}
}

Expand Down
8 changes: 4 additions & 4 deletions test/e2e/test_cases/test_cases.json
Original file line number Diff line number Diff line change
Expand Up @@ -2123,7 +2123,7 @@
"refs": ["11d5543"]
},
"ww_noFade/wNoFade_Tests/1_des_pol/area/04b_are": {
"refs": ["f14caf3"]
"refs": ["d4a01ec"]
},
"ww_noFade/wNoFade_Tests/1_des_pol/area/06a_are": {
"refs": ["8500722"]
Expand Down Expand Up @@ -2243,7 +2243,7 @@
"refs": ["174b9e0"]
},
"ww_noFade/wNoFade_Tests/1_des_pol/rectangle/04b_rec_1c": {
"refs": ["dacfe19"]
"refs": ["408884e"]
},
"ww_noFade/wNoFade_Tests/1_des_pol/rectangle/04b_rec_2c": {
"refs": ["206f7f9"]
Expand Down Expand Up @@ -2501,7 +2501,7 @@
"refs": ["d3fda3c"]
},
"ww_noFade/wNoFade_cases/1_des_pol/circle-rectangle/04_cir": {
"refs": ["417a34a"]
"refs": ["109cec8"]
},
"ww_noFade/wNoFade_cases/1_des_pol/circle-rectangle/05_cir": {
"refs": ["8296987"]
Expand Down Expand Up @@ -3236,7 +3236,7 @@
"refs": ["bd104b0"]
},
"web_content/cookbook/style/dark_theme": {
"refs": ["2d08a18"]
"refs": ["91f471a"]
},
"web_content/cookbook/style/highligh_markers": {
"refs": ["48d6207"]
Expand Down
3 changes: 3 additions & 0 deletions test/e2e/tests/config_tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
},
"dimension_axis_title": {
"refs": ["d9bab94"]
},
"dimension_axis_density": {
"refs": ["9b330fb"]
}
}
}
77 changes: 77 additions & 0 deletions test/e2e/tests/config_tests/dimension_axis_density.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const testSteps = [
(chart) =>
chart.animate({
data: {
series: [
{
name: 'C',
type: 'dimension',
values: [
'1',
'2',
'3',
'3,5',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12'
]
},
{
name: 'Values 2',
type: 'measure',
values: [1, 2, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 11, 12]
}
],
filter: (record) => record.C !== '3,5'
}
}),
(chart) =>
chart.animate(
{
x: { set: 'C', title: 'Step: 1' },
y: 'Values 2',
color: 'C',
legend: 'color'
},
0
)
]

for (let i = 1; i <= 5; i++) {
for (let j = 12 / i - 1; j >= 1; j--) {
const num = (i * j + 1) / (j - 0.0000001)
testSteps.push((chart) =>
chart.animate(
{
x: {
step: num,
title: 'Step: ' + Math.round(num * 1000) / 1000
}
},
0.3
)
)
}
}

for (let i = 6; i <= 12; i++) {
testSteps.push((chart) =>
chart.animate(
{
x: {
step: i,
title: 'Step: ' + i
}
},
0.3
)
)
}

export default testSteps