Skip to content

Commit 3c6b916

Browse files
authored
Merge pull request #617 from vizzuhq/axis_refactor_santa_special
Axis refactor v11e - Cross interlacing, NaN handling, off dimLabel out
2 parents 5ff6c82 + 0219fba commit 3c6b916

File tree

22 files changed

+372
-107
lines changed

22 files changed

+372
-107
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
- Enable dimension axis ticks and interlacing.
2828
- Enable measure axis guides.
2929
- Fix dimension axis guides on sorted chart.
30+
- Fix NaN handling on axes and size measures other aggregators than sum.
31+
- Add meaning to crossing interlacing.
32+
- Do not draw dimension axis labels when the middle of the text is off the plot.
3033

3134
## [0.15.0] - 2024-10-28
3235

src/base/type/uniquelist.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ template <class T> class UniqueList
237237
struct CommonIterateVal
238238
{
239239
const T &value;
240-
const std::size_t *othIx;
240+
const std::size_t *otherIx;
241241
};
242242

243243
struct common_iterator

src/chart/generator/axis.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,9 @@ bool DimensionAxis::setLabels(double step)
287287
auto currStep = 0.0;
288288

289289
for (auto curr = int{}; auto &&item : sortedItems()) {
290-
if (++curr <= currStep) continue;
290+
if (auto mid = item.get().range.middle();
291+
std::signbit(mid) || mid > 1.0 || ++curr <= currStep)
292+
continue;
291293
currStep += step;
292294
item.get().label = true;
293295
hasLabel = true;

src/chart/generator/axis.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ struct ChannelStats
4040

4141
void track(ChannelId at, const double &value)
4242
{
43-
std::get<0>(tracked[at]).include(value);
43+
if (std::isfinite(value))
44+
std::get<0>(tracked[at]).include(value);
4445
}
4546

4647
template <ChannelIdLike Id>

src/chart/generator/buckets.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ struct Buckets
4444
});
4545
}
4646

47-
[[nodiscard]] bool operator!=(const const_iterator &oth) const
47+
[[nodiscard]] bool operator!=(
48+
const const_iterator &other) const
4849
{
49-
return data.data() != oth.data.data();
50+
return data.data() != other.data.data();
5051
}
5152

5253
const_iterator &operator++();

src/chart/generator/marker.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ Marker::Marker(const Options &options,
140140
data.joinDimensionValues(labelChannel.dimensions(),
141141
index)};
142142
}
143+
144+
if (!std::isfinite(position.x) || !std::isfinite(position.y))
145+
enabled = false;
143146
}
144147

145148
bool Marker::connectMarkers(bool first,

src/chart/generator/plotbuilder.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,16 @@ PlotBuilder::PlotBuilder(const Data::DataTable &dataTable,
4848
std::size_t mainBucketSize{};
4949
auto &&subBuckets = generateMarkers(mainBucketSize);
5050

51-
if (!plot->getOptions()->getChannels().anyAxisSet())
51+
if (!plot->getOptions()->getChannels().anyAxisSet()) {
5252
addSpecLayout(subBuckets);
53-
else
53+
normalizeSizes();
54+
}
55+
else {
56+
normalizeSizes();
5457
addAxisLayout(subBuckets, mainBucketSize, dataTable);
58+
}
5559

5660
normalizeColors();
57-
normalizeSizes();
5861
calcLegendAndLabel(dataTable);
5962
}
6063

@@ -551,8 +554,11 @@ void PlotBuilder::normalizeSizes()
551554
|| plot->getOptions()->geometry == ShapeType::line) {
552555
Math::Range<> size;
553556

554-
for (auto &marker : plot->markers)
555-
if (marker.enabled) size.include(marker.sizeFactor);
557+
for (auto &marker : plot->markers) {
558+
if (std::isnan(marker.sizeFactor)) marker.enabled = false;
559+
if (!marker.enabled) continue;
560+
size.include(marker.sizeFactor);
561+
}
556562

557563
size = plot->getOptions()
558564
->getChannels()

src/chart/rendering/drawaxes.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ const DrawAxes &&DrawAxes::init() &&
101101
!item.startPos.isAuto() && *item.startPos,
102102
!item.endPos.isAuto() && *item.endPos,
103103
axis.dimension.factor);
104-
needSeparators && sepWeight > 0)
104+
needSeparators && sepWeight > 0
105+
&& item.range.getMin() > 0)
105106
separators.emplace_back(item.range.getMin(),
106107
sepWeight);
107108
}

src/chart/rendering/drawinterlacing.cpp

Lines changed: 115 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ void DrawInterlacing::drawGeometries(Gen::AxisId axisIndex) const
3434
|| guides.interlacings == false)
3535
return;
3636

37-
auto orientation = !+axisIndex;
37+
auto otherWeights = getInterlacingWeights(!axisIndex);
38+
auto &&otherInterlacingColor =
39+
*parent.rootStyle.plot.getAxis(!axisIndex).interlacing.color;
3840

3941
parent.painter.setPolygonToCircleFactor(0);
4042
parent.painter.setPolygonStraightFactor(0);
@@ -48,30 +50,42 @@ void DrawInterlacing::drawGeometries(Gen::AxisId axisIndex) const
4850
1.0,
4951
Math::Floating::less)
5052
- clippedBottom;
51-
auto rect = Geom::Rect{
52-
Geom::Point::Coord(orientation, 0.0, clippedBottom),
53-
{Geom::Size::Coord(orientation, 1.0, clippedSize)}};
54-
55-
auto interlacingColor =
56-
*axisStyle.interlacing.color
57-
* Math::FuzzyBool::And<double>(interval.weight,
58-
interval.isSecond,
59-
guides.interlacings);
60-
61-
auto &canvas = parent.canvas;
62-
canvas.save();
63-
canvas.setLineColor(Gfx::Color::Transparent());
64-
canvas.setBrushColor(interlacingColor);
65-
if (auto &&eventTarget =
66-
Events::Targets::axisInterlacing(axisIndex);
67-
parent.rootEvents.draw.plot.axis.interlacing->invoke(
68-
Events::OnRectDrawEvent(*eventTarget,
69-
{rect, true}))) {
70-
parent.painter.drawPolygon(rect.points());
71-
parent.renderedChart.emplace(Rect{rect, true},
72-
std::move(eventTarget));
53+
54+
auto rect = [&, orientation = +axisIndex](const double &from,
55+
const double &to)
56+
{
57+
return Geom::Rect{
58+
Geom::Point::Coord(orientation, clippedBottom, from),
59+
{Geom::Size::Coord(orientation,
60+
clippedSize,
61+
to - from)}};
62+
};
63+
64+
auto weight = Math::FuzzyBool::And<double>(interval.weight,
65+
interval.isSecond,
66+
guides.interlacings);
67+
auto interlacingColor = *axisStyle.interlacing.color * weight;
68+
69+
for (auto first = otherWeights.begin(),
70+
next = std::next(first),
71+
last = otherWeights.end();
72+
next != last;
73+
++next, ++first) {
74+
if (Math::Floating::is_zero(first->second))
75+
drawInterlacing(axisIndex,
76+
interlacingColor,
77+
rect(first->first, next->first));
78+
else if (axisIndex == Gen::AxisId::y) {
79+
drawInterlacing(first->second > weight ? !axisIndex
80+
: axisIndex,
81+
getCrossingInterlacingColor(
82+
*axisStyle.interlacing.color,
83+
weight,
84+
otherInterlacingColor,
85+
first->second),
86+
rect(first->first, next->first));
87+
}
7388
}
74-
canvas.restore();
7589
}
7690
}
7791

@@ -119,6 +133,26 @@ void DrawInterlacing::drawTexts(Gen::AxisId axisIndex) const
119133
}
120134
}
121135

136+
void DrawInterlacing::drawInterlacing(Gen::AxisId axisIndex,
137+
const Gfx::Color &interlacingColor,
138+
const Geom::Rect &rect) const
139+
{
140+
auto &canvas = parent.canvas;
141+
canvas.save();
142+
canvas.setLineColor(Gfx::Color::Transparent());
143+
canvas.setLineWidth(0);
144+
canvas.setBrushColor(interlacingColor);
145+
if (auto &&eventTarget =
146+
Events::Targets::axisInterlacing(axisIndex);
147+
parent.rootEvents.draw.plot.axis.interlacing->invoke(
148+
Events::OnRectDrawEvent(*eventTarget, {rect, true}))) {
149+
parent.painter.drawPolygon(rect.points());
150+
parent.renderedChart.emplace(Rect{rect, true},
151+
std::move(eventTarget));
152+
}
153+
canvas.restore();
154+
}
155+
122156
void DrawInterlacing::drawDataLabel(
123157
const ::Anim::Interpolated<bool> &axisEnabled,
124158
Gen::AxisId axisIndex,
@@ -226,4 +260,61 @@ void DrawInterlacing::drawSticks(double tickLength,
226260
canvas.restore();
227261
}
228262

263+
std::map<double, double> DrawInterlacing::getInterlacingWeights(
264+
Gen::AxisId axisIndex) const
265+
{
266+
std::map<double, double> weights{{0.0, 0.0}, {1.0, 0.0}};
267+
268+
auto &&guides = parent.plot->guides.at(axisIndex);
269+
auto &&axisStyle = parent.rootStyle.plot.getAxis(axisIndex);
270+
if (axisStyle.interlacing.color->isTransparent()
271+
|| guides.interlacings == false)
272+
return weights;
273+
274+
for (auto &&interval : parent.getIntervals(axisIndex)) {
275+
if (Math::Floating::is_zero(interval.isSecond)) continue;
276+
auto min = std::max(interval.range.getMin(), 0.0);
277+
auto max = std::min(interval.range.getMax(), 1.0);
278+
auto mprev = std::prev(weights.upper_bound(min));
279+
auto mnext = weights.lower_bound(max);
280+
281+
if (mprev->first < min)
282+
mprev = weights.try_emplace(mprev, min, mprev->second);
283+
if (mnext->first > max)
284+
mnext = weights.try_emplace(mnext,
285+
max,
286+
std::prev(mnext)->second);
287+
288+
while (mprev != mnext)
289+
mprev++->second +=
290+
Math::FuzzyBool::And<double>(interval.weight,
291+
interval.isSecond,
292+
guides.interlacings);
293+
}
294+
return weights;
295+
}
296+
297+
Gfx::Color DrawInterlacing::getCrossingInterlacingColor(
298+
const Gfx::Color &mainColor,
299+
double mainWeight,
300+
const Gfx::Color &otherColor,
301+
double otherWeight)
302+
{
303+
auto color = mainColor * mainWeight + otherColor * otherWeight;
304+
305+
color.alpha = 1
306+
- (1 - mainColor.alpha * mainWeight)
307+
* (1 - otherColor.alpha * otherWeight);
308+
309+
if (mainWeight + otherWeight > 1.0)
310+
color = Math::Niebloid::interpolate(color,
311+
color
312+
* std::max({std::abs(mainColor.red - otherColor.red),
313+
std::abs(mainColor.green - otherColor.green),
314+
std::abs(mainColor.blue - otherColor.blue)}),
315+
mainWeight + otherWeight - 1.0);
316+
317+
return color;
318+
}
319+
229320
}

src/chart/rendering/drawinterlacing.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ class DrawInterlacing
1616
const DrawAxes &parent;
1717

1818
private:
19+
void drawInterlacing(Gen::AxisId axisIndex,
20+
const Gfx::Color &interlacingColor,
21+
const Geom::Rect &rect) const;
22+
1923
void drawDataLabel(const ::Anim::Interpolated<bool> &enabled,
2024
Gen::AxisId axisIndex,
2125
const Geom::Point &tickPos,
@@ -27,6 +31,15 @@ class DrawInterlacing
2731
const Gfx::Color &tickColor,
2832
Gen::AxisId axisIndex,
2933
const Geom::Point &tickPos) const;
34+
35+
[[nodiscard]] std::map<double, double> getInterlacingWeights(
36+
Gen::AxisId axisIndex) const;
37+
38+
[[nodiscard]] static Gfx::Color getCrossingInterlacingColor(
39+
const Gfx::Color &mainColor,
40+
double mainWeight,
41+
const Gfx::Color &otherColor,
42+
double otherWeight);
3043
};
3144

3245
}

0 commit comments

Comments
 (0)