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

Add get_min_max() to Perspective API #1395

Merged
merged 2 commits into from
Apr 26, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Add get_min_max() to perspective API
  • Loading branch information
texodus committed Apr 26, 2021
commit 6fd5a104759e60f103ca8ee43bfee8f437e27950
43 changes: 43 additions & 0 deletions cpp/perspective/src/cpp/context_one.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,49 @@ t_ctx1::close(t_index idx) {
return retval;
}

std::pair<t_tscalar, t_tscalar>
t_ctx1::get_min_max(const std::string& colname) const {
auto rval = std::make_pair(mknone(), mknone());
auto aggtable = m_tree->get_aggtable();
t_schema aggschema = aggtable->get_schema();
auto col = aggtable->get_const_column(colname).get();
auto colidx = aggschema.get_colidx(colname);
auto depth = m_config.get_num_rpivots();
const std::vector<t_aggspec>& aggspecs = m_config.get_aggregates();
bool is_finished = false;
while (!is_finished && depth > 0) {
for (std::size_t i = 0; i < m_traversal->size(); i++) {
t_index nidx = m_traversal->get_tree_index(i);
t_index pnidx = m_tree->get_parent_idx(nidx);
if (m_tree->get_depth(nidx) != depth) {
continue;
}

t_uindex agg_ridx = m_tree->get_aggidx(nidx);
t_index agg_pridx = pnidx == INVALID_INDEX ? INVALID_INDEX : m_tree->get_aggidx(pnidx);
t_tscalar val
= extract_aggregate(aggspecs[colidx], col, agg_ridx, agg_pridx);

if (!val.is_valid()) {
continue;
}

is_finished = true;
if (rval.first.is_none() || (!val.is_none() && val < rval.first)) {
rval.first = val;
}

if (val > rval.second) {
rval.second = val;
}
}

depth--;
}

return rval;
}

std::vector<t_tscalar>
t_ctx1::get_data(t_index start_row, t_index end_row, t_index start_col, t_index end_col) const {
PSP_TRACE_SENTINEL();
Expand Down
81 changes: 81 additions & 0 deletions cpp/perspective/src/cpp/context_two.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,87 @@ t_ctx2::get_ctraversal_indices() const {
return std::vector<t_index>();
}

std::pair<t_tscalar, t_tscalar>
t_ctx2::get_min_max(const std::string& colname) const {
t_uindex ctx_nrows = get_row_count();
t_uindex ctx_ncols = get_column_count();
auto rval = std::make_pair(mknone(), mknone());
t_uindex scol = m_trees[0]->get_aggtable()->get_schema().get_colidx(colname);
std::vector<std::pair<t_uindex, t_uindex>> cells;
for (t_index ridx = 0; ridx < ctx_nrows; ++ridx) {
for (t_index cidx = 0; cidx < ctx_ncols; ++cidx) {
cells.push_back(
std::pair<t_index, t_index>(ridx, cidx));
}
}

auto cells_info = resolve_cells(cells);
typedef std::pair<t_uindex, t_uindex> t_aggpair;
std::map<t_aggpair, const t_column*> aggmap;
auto n_aggs = m_config.get_num_aggregates();
for (t_uindex treeidx = 0, tree_loop_end = m_trees.size(); treeidx < tree_loop_end;
++treeidx) {
auto aggtable = m_trees[treeidx]->get_aggtable();
t_schema aggschema = aggtable->get_schema();
for (t_uindex aggidx = 0, agg_loop_end = n_aggs;
aggidx < agg_loop_end; ++aggidx) {
const std::string& aggname = aggschema.m_columns[aggidx];
aggmap[t_aggpair(treeidx, aggidx)] = aggtable->get_const_column(aggname).get();
}
}

const std::vector<t_aggspec>& aggspecs = m_config.get_aggregates();
bool is_finished = false;
t_uindex row_depth = m_row_depth + 1;
while (!is_finished && row_depth > 0) {
for (std::size_t i = 0; i < cells_info.size(); ++i) {
const t_cellinfo& cinfo = cells_info[i];
if (cinfo.m_idx < 0 || cinfo.m_agg_index != scol) {
continue;
} else {
t_index nidx = m_rtraversal->get_tree_index(cinfo.m_ridx);
if (rtree()->get_depth(nidx) != row_depth) {
continue;
}

auto col_depth
= ctree()->get_depth(m_ctraversal->get_tree_index(
calc_translated_colidx(n_aggs, cinfo.m_cidx)));
if (m_config.get_num_cpivots() != col_depth) {
continue;
}

auto aggcol = aggmap[t_aggpair(cinfo.m_treenum, cinfo.m_agg_index)];
t_index p_idx = m_trees[cinfo.m_treenum]->get_parent_idx(cinfo.m_idx);
t_uindex agg_ridx = m_trees[cinfo.m_treenum]->get_aggidx(cinfo.m_idx);
t_uindex agg_pridx = p_idx == INVALID_INDEX
? INVALID_INDEX
: m_trees[cinfo.m_treenum]->get_aggidx(p_idx);

auto val = extract_aggregate(
aggspecs[cinfo.m_agg_index], aggcol, agg_ridx, agg_pridx);

if (!val.is_valid()) {
continue;
}

is_finished = true;
if (rval.first.is_none() || (!val.is_none() && val < rval.first)) {
rval.first = val;
}

if (val > rval.second) {
rval.second = val;
}
}
}

row_depth--;
}

return rval;
}

std::vector<t_tscalar>
t_ctx2::get_data(t_index start_row, t_index end_row, t_index start_col, t_index end_col) const {
t_uindex ctx_nrows = get_row_count();
Expand Down
22 changes: 22 additions & 0 deletions cpp/perspective/src/cpp/context_unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,28 @@ t_ctxunit::notify(const t_data_table& flattened) {
}
}

std::pair<t_tscalar, t_tscalar>
t_ctxunit::get_min_max(const std::string& colname) const {
auto col = m_gstate->get_table()->get_const_column(colname);
auto rval = std::make_pair(mknone(), mknone());
for (std::size_t i = 0; i < col->size(); i++) {
t_tscalar val = col->get_scalar(i);
if (!val.is_valid()) {
continue;
}

if (rval.first.is_none() || (!val.is_none() && val < rval.first)) {
rval.first = val;
}

if (val > rval.second) {
rval.second = val;
}
}

return rval;
}

/**
* @brief Given a start/end row and column, return the data for the subset.
*
Expand Down
33 changes: 33 additions & 0 deletions cpp/perspective/src/cpp/context_zero.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,39 @@ t_ctx0::notify(const t_data_table& flattened) {
}
}

/**
* @brief Gives the min and max value (by t_tscalar comparison) of the leaf
* nodes of a given column.
*
* @param colname
* @return std::pair<t_tscalar, t_tscalar>
*/
std::pair<t_tscalar, t_tscalar>
t_ctx0::get_min_max(const std::string& colname) const {
std::pair<t_tscalar, t_tscalar> rval(mknone(), mknone());
t_uindex ctx_nrows = get_row_count();
std::vector<t_tscalar> values(ctx_nrows);
std::vector<t_tscalar> pkeys = m_traversal->get_pkeys(0, ctx_nrows);
std::vector<t_tscalar> out_data(pkeys.size());
m_gstate->read_column(colname, pkeys, out_data);
for (t_index ridx = 0; ridx < m_traversal->size(); ++ridx) {
auto val = out_data[ridx];
if (!val.is_valid()) {
continue;
}

if (rval.first.is_none() || (!val.is_none() && val < rval.first)) {
rval.first = val;
}

if (val > rval.second) {
rval.second = val;
}
}

return rval;
}

/**
* @brief Given a start/end row and column index, return the underlying data
* for the requested subset.
Expand Down
14 changes: 14 additions & 0 deletions cpp/perspective/src/cpp/emscripten.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1739,6 +1739,16 @@ namespace binding {
return scalar_to_val(d);
}

template <typename CTX_T>
t_val
get_min_max(std::shared_ptr<View<CTX_T>> view, const std::string& colname) {
t_val arr = t_val::array();
std::pair<t_tscalar, t_tscalar> min_max = view->get_min_max(colname);
arr.set(0, scalar_to_val(min_max.first));
arr.set(1, scalar_to_val(min_max.second));
return arr;
}

} // end namespace binding
} // end namespace perspective

Expand Down Expand Up @@ -2214,6 +2224,10 @@ EMSCRIPTEN_BINDINGS(perspective) {
function("get_from_data_slice_one", &get_from_data_slice<t_ctx1>, allow_raw_pointers());
function("get_data_slice_two", &get_data_slice<t_ctx2>, allow_raw_pointers());
function("get_from_data_slice_two", &get_from_data_slice<t_ctx2>, allow_raw_pointers());
function("get_min_max_unit", &get_min_max<t_ctxunit>);
function("get_min_max_zero", &get_min_max<t_ctx0>);
function("get_min_max_one", &get_min_max<t_ctx1>);
function("get_min_max_two", &get_min_max<t_ctx2>);
function("to_arrow_unit", &to_arrow<t_ctxunit>);
function("to_arrow_zero", &to_arrow<t_ctx0>);
function("to_arrow_one", &to_arrow<t_ctx1>);
Expand Down
6 changes: 6 additions & 0 deletions cpp/perspective/src/cpp/view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,12 @@ View<t_ctx0>::computed_schema() const {
return new_schema;
}

template <typename T>
std::pair<t_tscalar, t_tscalar>
View<T>::get_min_max(const std::string& colname) const {
return m_ctx->get_min_max(colname);
}

template <>
std::shared_ptr<t_data_slice<t_ctxunit>>
View<t_ctxunit>::get_data(
Expand Down
2 changes: 2 additions & 0 deletions cpp/perspective/src/include/perspective/context_one.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class PERSPECTIVE_EXPORT t_ctx1 : public t_ctxbase<t_ctx1> {

t_depth get_trav_depth(t_index idx) const;

std::pair<t_tscalar, t_tscalar> get_min_max(const std::string& colname) const;

using t_ctxbase<t_ctx1>::get_data;

private:
Expand Down
2 changes: 2 additions & 0 deletions cpp/perspective/src/include/perspective/context_two.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class PERSPECTIVE_EXPORT t_ctx2 : public t_ctxbase<t_ctx2> {

void set_depth(t_header header, t_depth depth);

std::pair<t_tscalar, t_tscalar> get_min_max(const std::string& colname) const;

using t_ctxbase<t_ctx2>::get_data;

protected:
Expand Down
2 changes: 2 additions & 0 deletions cpp/perspective/src/include/perspective/context_unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class PERSPECTIVE_EXPORT t_ctxunit : public t_ctxbase<t_ctxunit> {

perspective::t_index get_column_count() const;

std::pair<t_tscalar, t_tscalar> get_min_max(const std::string& colname) const;

using t_ctxbase<t_ctxunit>::get_data;

std::vector<t_tscalar> get_data(
Expand Down
2 changes: 2 additions & 0 deletions cpp/perspective/src/include/perspective/context_zero.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class PERSPECTIVE_EXPORT t_ctx0 : public t_ctxbase<t_ctx0> {
void sort_by();
std::vector<t_sortspec> get_sort_by() const;

std::pair<t_tscalar, t_tscalar> get_min_max(const std::string& colname) const;

using t_ctxbase<t_ctx0>::get_data;

protected:
Expand Down
7 changes: 7 additions & 0 deletions cpp/perspective/src/include/perspective/view.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ class PERSPECTIVE_EXPORT View {
*/
std::vector<std::vector<t_tscalar>> column_paths() const;

/**
* @brief
*
* @return std::pair<t_tscalar, t_tscalar>
*/
std::pair<t_tscalar, t_tscalar> get_min_max(const std::string& colname) const;

/**
* @brief Returns shared pointer to a t_data_slice object, which contains the
* underlying slice of data as well as the metadata required to interface
Expand Down
3 changes: 1 addition & 2 deletions packages/perspective-viewer-datagrid/src/js/plugin_menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ import chroma from "chroma-js";

export const PLUGIN_SYMBOL = Symbol("Plugin Symbol");

export function activate_plugin_menu(regularTable, target, maxes) {
export function activate_plugin_menu(regularTable, target, column_max) {
const target_meta = regularTable.getMeta(target);
const column_name = target_meta.column_header[target_meta.column_header.length - 1];
const column_type = this._schema[column_name];
const column_max = maxes[column_name];
const default_config = {
gradient: column_max,
pos_color: this._pos_color[0],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,16 +98,6 @@ function styleListener(regularTable) {
const metadata = regularTable.getMeta(td);
const column_name = metadata.column_header?.[metadata.column_header?.length - 1];
const plugin = plugins[column_name];
if (this._calc_range_flag) {
const is_leaf = metadata.row_header.length === 0 || metadata.row_header[metadata.row_header.length - 1] !== undefined;
if (is_leaf) {
let column_meta = this._cached_range[column_name];
let max = Math.max(column_meta || -Infinity, Math.abs(metadata.user) || -Infinity);
if (isFinite(max)) {
this._cached_range[column_name] = max;
}
}
}

let type = get_psp_type.call(this, metadata);
const is_numeric = type === "integer" || type === "float";
Expand Down Expand Up @@ -263,13 +253,11 @@ async function mousedownListener(regularTable, event) {
} else if (target.classList.contains("psp-menu-enabled")) {
const rect = target.getBoundingClientRect();
if (event.clientY - rect.top > 16) {
this._calc_range_flag = true;
const meta = regularTable.getMeta(target);
const column_name = meta.column_header?.[meta.column_header?.length - 1];
const [, max] = await this._view.get_min_max(column_name);
this._open_column_styles_menu.unshift(meta._virtual_x);
await regularTable.draw();
this._calc_range_flag = undefined;
const maxes = this._cached_range;
activate_plugin_menu.call(this, regularTable, target, maxes);
activate_plugin_menu.call(this, regularTable, target, max);
event.preventDefault();
} else {
sortHandler.call(this, regularTable, event, target);
Expand Down Expand Up @@ -417,7 +405,6 @@ export async function createModel(regular, table, view, extend = {}) {
_num_rows: num_rows,
_schema: {...schema, ...computed_schema},
_ids: [],
_cached_range: {},
_open_column_styles_menu: [],
_plugin_background,
_pos_color,
Expand Down
2 changes: 2 additions & 0 deletions packages/perspective/src/js/api/view_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ proxy_view.prototype = view.prototype;

view.prototype.get_config = async_queue("get_config");

view.prototype.get_min_max = async_queue("get_min_max");

view.prototype.to_json = async_queue("to_json");

view.prototype.to_arrow = async_queue("to_arrow");
Expand Down
17 changes: 17 additions & 0 deletions packages/perspective/src/js/perspective.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,23 @@ export default function(Module) {
return options;
};

/**
* Calculates the [min, max] of the leaf nodes of a column `colname`.
*
* @param {String} colname A column name in this `View`.
* @returns {Array<Object>} A tuple of [min, max], whose types are column
* and aggregate dependent.
*/
view.prototype.get_min_max = function(colname) {
if (this.is_unit_context) {
return __MODULE__.get_min_max_unit(this._View, colname);
} else {
const num_sides = this.sides();
const nidx = SIDES[num_sides];
return __MODULE__[`get_min_max_${nidx}`](this._View, colname);
}
};

/**
* Generic base function from which `to_json`, `to_columns` etc. derives.
*
Expand Down
Loading