Skip to content

Commit 5065cde

Browse files
authored
Merge pull request #3180 from perspective-dev/gmv-aggregate
Add `gmv` aggregate
2 parents 643b74a + 7e6aa10 commit 5065cde

11 files changed

Lines changed: 346 additions & 3 deletions

File tree

.github/workflows/build.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ on:
2828
- docs/
2929
- examples/
3030
- rust/perspective-python/README.md
31-
pull_request_target:
31+
pull_request:
3232
branches:
3333
- master
3434
workflow_dispatch:

rust/perspective-python/perspective/tests/table/test_view.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,151 @@ def test_view_aggregate_mean(self):
424424
{"__ROW_PATH__": ["a"], "y": 300 / 2},
425425
]
426426

427+
def test_view_aggregate_gmv(self):
428+
data = {
429+
"division": [
430+
"D1",
431+
"D2",
432+
"D1",
433+
"D2",
434+
"D1",
435+
"D2",
436+
"D1",
437+
"D2",
438+
"D1",
439+
"D2",
440+
"D1",
441+
"D2",
442+
"D1",
443+
"D2",
444+
"D1",
445+
"D2",
446+
"D1",
447+
"D2",
448+
"D1",
449+
"D2",
450+
],
451+
"trading area": [
452+
"A",
453+
"B",
454+
"C",
455+
"D",
456+
"E",
457+
"A",
458+
"B",
459+
"C",
460+
"D",
461+
"E",
462+
"A",
463+
"B",
464+
"C",
465+
"D",
466+
"E",
467+
"A",
468+
"B",
469+
"C",
470+
"D",
471+
"E",
472+
],
473+
"symbol": [
474+
"AAPL",
475+
"GOOG",
476+
"MSFT",
477+
"AAPL",
478+
"GOOG",
479+
"MSFT",
480+
"AAPL",
481+
"GOOG",
482+
"MSFT",
483+
"AAPL",
484+
"GOOG",
485+
"MSFT",
486+
"AAPL",
487+
"GOOG",
488+
"MSFT",
489+
"AAPL",
490+
"GOOG",
491+
"MSFT",
492+
"AAPL",
493+
"GOOG",
494+
],
495+
"MV": [
496+
1500,
497+
1200,
498+
1300,
499+
1400,
500+
1600,
501+
1100,
502+
1700,
503+
1800,
504+
1900,
505+
2000,
506+
-2100,
507+
-2200,
508+
-2300,
509+
-2400,
510+
-2500,
511+
-2600,
512+
-2700,
513+
-2800,
514+
-2900,
515+
-3000,
516+
],
517+
}
518+
519+
tbl = Table(data)
520+
view = tbl.view(
521+
aggregates={"MV": "gmv"}, group_by=["division", "symbol"], columns=["MV"]
522+
)
523+
524+
assert view.to_columns() == {
525+
"__ROW_PATH__": [
526+
[],
527+
["D1"],
528+
["D1", "AAPL"],
529+
["D1", "GOOG"],
530+
["D1", "MSFT"],
531+
["D2"],
532+
["D2", "AAPL"],
533+
["D2", "GOOG"],
534+
["D2", "MSFT"],
535+
],
536+
"MV": [10000, 5900, -2000, -3200, 700, 7100, 800, -2400, -3900],
537+
}
538+
539+
def test_view_aggregate_gmv_split_by(self):
540+
data = {
541+
"division": [
542+
"D1", "D2", "D1", "D2", "D1", "D2", "D1", "D2", "D1", "D2",
543+
"D1", "D2", "D1", "D2", "D1", "D2", "D1", "D2", "D1", "D2",
544+
],
545+
"symbol": [
546+
"AAPL", "GOOG", "MSFT", "AAPL", "GOOG", "MSFT", "AAPL",
547+
"GOOG", "MSFT", "AAPL", "GOOG", "MSFT", "AAPL", "GOOG",
548+
"MSFT", "AAPL", "GOOG", "MSFT", "AAPL", "GOOG",
549+
],
550+
"MV": [
551+
1500, 1200, 1300, 1400, 1600, 1100, 1700, 1800, 1900, 2000,
552+
-2100, -2200, -2300, -2400, -2500, -2600, -2700, -2800,
553+
-2900, -3000,
554+
],
555+
}
556+
557+
tbl = Table(data)
558+
view = tbl.view(
559+
aggregates={"MV": "gmv"},
560+
group_by=["division"],
561+
split_by=["symbol"],
562+
columns=["MV"],
563+
)
564+
565+
assert view.to_columns() == {
566+
"__ROW_PATH__": [[], ["D1"], ["D2"]],
567+
"AAPL|MV": [2800, -2000, 800],
568+
"GOOG|MV": [5600, -3200, -2400],
569+
"MSFT|MV": [4600, 700, -3900],
570+
}
571+
427572
def test_view_aggregate_mean_from_schema(self):
428573
data = [
429574
{"a": "a", "x": 1, "y": 200},

rust/perspective-server/cpp/perspective/src/cpp/aggspec.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ t_aggspec::agg_str() const {
247247
case AGGTYPE_STANDARD_DEVIATION: {
248248
return "stddev";
249249
}
250+
case AGGTYPE_GMV: {
251+
return "gmv";
252+
}
250253
default: {
251254
PSP_COMPLAIN_AND_ABORT("Unknown agg type");
252255
return "unknown";
@@ -343,6 +346,7 @@ t_aggspec::get_output_specs(const t_schema& schema) const {
343346
case AGGTYPE_SUM:
344347
case AGGTYPE_SUM_ABS:
345348
case AGGTYPE_ABS_SUM:
349+
case AGGTYPE_GMV:
346350
case AGGTYPE_PCT_SUM_PARENT:
347351
case AGGTYPE_PCT_SUM_GRAND_TOTAL:
348352
case AGGTYPE_MUL:

rust/perspective-server/cpp/perspective/src/cpp/base.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,9 @@ str_to_aggtype(const std::string& str) {
589589
if (str == "stddev" || str == "standard deviation") {
590590
return t_aggtype::AGGTYPE_STANDARD_DEVIATION;
591591
}
592+
if (str == "gmv") {
593+
return t_aggtype::AGGTYPE_GMV;
594+
}
592595

593596
std::stringstream ss;
594597
ss << "Encountered unknown aggregate operation: '" << str << "'"

rust/perspective-server/cpp/perspective/src/cpp/config.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ t_config::setup(
226226
case AGGTYPE_SUM_NOT_NULL:
227227
case AGGTYPE_SUM_ABS:
228228
case AGGTYPE_ABS_SUM:
229+
case AGGTYPE_GMV:
229230
case AGGTYPE_MUL:
230231
case AGGTYPE_DISTINCT_COUNT:
231232
case AGGTYPE_DISTINCT_LEAF:

rust/perspective-server/cpp/perspective/src/cpp/context_two.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ t_ctx2::init() {
7777
);
7878

7979
m_trees[treeidx]->init();
80+
81+
// Tell the tree how many of its `m_pivots` are row pivots and
82+
// what the next missing row pivot is (if any). AGGTYPE_GMV uses
83+
// this to roll up across row dimensions that aren't embedded in
84+
// this particular tree — e.g. m_trees[0] has no row pivots, so
85+
// a tree-leaf at e.g. [AAPL] needs to be partitioned by
86+
// `row_pivots[0]` from the gstate to compute the gmv value.
87+
const auto& row_pivots = m_config.get_row_pivots();
88+
std::string next_row_pivot;
89+
if (treeidx < row_pivots.size()) {
90+
next_row_pivot = row_pivots[treeidx].colname();
91+
}
92+
m_trees[treeidx]->set_gmv_row_pivot_meta(treeidx, next_row_pivot);
8093
}
8194

8295
m_rtraversal = std::make_shared<t_traversal>(rtree());
@@ -1171,6 +1184,15 @@ t_ctx2::reset(bool reset_expressions) {
11711184
);
11721185
m_trees[treeidx]->init();
11731186
m_trees[treeidx]->set_deltas_enabled(get_feature_state(CTX_FEAT_DELTA));
1187+
1188+
// See [t_ctx2::init] — gmv needs to know how many row pivots
1189+
// this particular tree carries vs. what's still in the gstate.
1190+
const auto& row_pivots = m_config.get_row_pivots();
1191+
std::string next_row_pivot;
1192+
if (treeidx < row_pivots.size()) {
1193+
next_row_pivot = row_pivots[treeidx].colname();
1194+
}
1195+
m_trees[treeidx]->set_gmv_row_pivot_meta(treeidx, next_row_pivot);
11741196
}
11751197

11761198
m_rtraversal = std::make_shared<t_traversal>(rtree());

rust/perspective-server/cpp/perspective/src/cpp/extract_aggregate.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ extract_aggregate(
5454
case AGGTYPE_SUM:
5555
case AGGTYPE_SUM_ABS:
5656
case AGGTYPE_ABS_SUM:
57+
case AGGTYPE_GMV:
5758
case AGGTYPE_SUM_NOT_NULL:
5859
case AGGTYPE_MUL:
5960
case AGGTYPE_COUNT:

rust/perspective-server/cpp/perspective/src/cpp/server.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,6 +1453,7 @@ ProtoServer::_handle_request(std::uint32_t client_id, Request&& req) {
14531453
number_opts.add_aggregates()->set_name("distinct count");
14541454
number_opts.add_aggregates()->set_name("dominant");
14551455
number_opts.add_aggregates()->set_name("first");
1456+
number_opts.add_aggregates()->set_name("gmv");
14561457
number_opts.add_aggregates()->set_name("high");
14571458
number_opts.add_aggregates()->set_name("low");
14581459
number_opts.add_aggregates()->set_name("max");

0 commit comments

Comments
 (0)