본문으로 건너뛰기
cccskills
무료GitHub에 공개

datagrok-selection

Manipulate row selection (`df.selection`) on a Datagrok DataFrame via the datagrok_exec tool — set, clear, invert, add to, remove from, intersect, and read the selection mask. Also covers current row (`df.currentRowIdx`), the cross-skill bridges to/from the filter, and how to materialize the selected rows as a new DataFrame. Use whenever the user says "select rows", "deselect", "invert selection", "highlight rows", "selected rows", "clear selection", "current row", "currentRowIdx", "count selected", "list selected indexes", "selection from filter", "filter from selection", or asks for selected rows as a new table. Does NOT cover row filtering (separate skill `datagrok-filtering`) or generic DataFrame cloning (`datagrok-df-and-columns`).

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(1)

  • SKILL.md15.8 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

datagrok-selection

The active DataFrame is t; row selection lives at t.selection (a DG.BitSet).

The number-one trap: t.selection.setAll(false) clears the selection. setAll(true) selects every row. That is the opposite of filter, where setAll(true) is the cleared / no-filter state.

Quick reference

NeedCode
select all rowst.selection.setAll(true)
clear the selectiont.selection.setAll(false)
invertt.selection.invert()
select by predicate (replace)t.selection.init(i => pred(i))
select by index list (replace)t.selection.setAll(false, false); for (const i of idx) t.selection.set(i,true,false); t.selection.fireChanged();
add by predicate (union)t.selection.or(DG.BitSet.create(t.rowCount, i => pred(i)))
remove indicesfor (const i of idx) t.selection.set(i,false,false); t.selection.fireChanged();
intersect with predicatet.selection.and(DG.BitSet.create(t.rowCount, i => pred(i)))
count selectedt.selection.trueCount
indices of selected rowst.selection.getSelectedIndexes() (returns Int32Array)
is row i selected?t.selection.get(i)
any row selected?t.selection.anyTrue
selected rows as a new DFt.clone(t.selection)
filter → selection (select visible)t.selection.copyFrom(t.filter)
selection → filter (hide unselected)t.filter.copyFrom(t.selection)
move current rowt.currentRowIdx = i (validate 0 <= i < t.rowCount)
current row object / cellt.currentRow, t.currentCell
mouse-over rowt.mouseOverRowIdx
subscribe to selection changesview.subs.push(t.onSelectionChanged.subscribe(() => …))

The polarity table — opposite of filter

Selection and filter use the same DG.BitSet class, but the meaning of true differs, so "clear" goes in opposite directions:

ActionFilter (df.filter)Selection (df.selection)
clear (return to default)setAll(true) (show all)setAll(false) (none selected)
meaning of bit === truerow passes (visible)row is selected
meaning of bit === falserow hiddenrow not selected

The pair to memorize, side by side:

t.filter.setAll(true);      // clear filter    → every row visible
t.selection.setAll(false);  // clear selection → none selected

Predicate polarity matches across skills: in both t.filter.init(pred) and t.selection.init(pred), returning true includes the row. Only the clear idiom flips.

Selection vs current row vs mouse-over

Three independent row pointers — none is "the selected row" in the singular:

ConceptAPICardinalityEvent
Selectiont.selection (BitSet)many rows (set)t.onSelectionChanged
Current rowt.currentRowIdx / t.currentRowone row (focus)t.onCurrentRowChanged
Mouse-overt.mouseOverRowIdxone row (transient)t.onMouseOverRowChanged

Setting t.currentRowIdx = 5 does not select row 5; selecting rows does not move the current row. When a user says "highlight row 5", the intent is ambiguous — pick the path matching context ("scroll to" → current row; "mark" → selection) or surface the ambiguity.

Reading selection state

NeedCode
rows currently selectedt.selection.trueCount
rows not selectedt.selection.falseCount
total rowst.selection.length (same as t.rowCount)
indices of selected rowst.selection.getSelectedIndexes() → Int32Array
is row i selected?t.selection.get(i)
any selected?t.selection.anyTrue
any unselected?t.selection.anyFalse
next / prev set bitt.selection.findNext(i, true) / findPrev(i, true)
// How many rows are currently selected?
return {selected: t.selection.trueCount, unselected: t.selection.falseCount, total: t.rowCount};

getSelectedIndexes() caches its result. The cache invalidates on public mutators (set, init, setAll, and/or/xor/andNot, invert, copyFrom). If you mutate via getBuffer(), call fireChanged() to invalidate.

Programmatic selection — modes

The four modes map directly to BitSet operations:

ModeBitSet opPattern
replaceinit(pred) / copyFrom(other)new selection replaces current
addor(other)union with current
removeandNot(other)subtract from current
intersectand(other)keep only rows in both

Predicate

t.selection.init(pred) is the fast, buffer-direct path for replace:

// Select rows where age > 40 (replace).
const age = t.getCol('age');
t.selection.init(i => (age.get(i)) > 40);
return {selected: t.selection.trueCount};

For add / remove / intersect with a predicate, build a fresh BitSet and combine:

// Add to the current selection (union, don't replace).
const act = t.getCol('activity');
t.selection.or(DG.BitSet.create(t.rowCount, i => (act.get(i)) > 7));

Index list

t.selection.set(i, x, notify) writes one bit. Pass notify=false in a loop, then call fireChanged() once — otherwise N writes fire N events:

// Select explicit indices (replace). Zero the buffer, set bits with notify=false,
// fire one change at the end.
const idx = [0, 3, 5, 7, 11];
t.selection.setAll(false, false);
for (const i of idx) t.selection.set(i, true, false);
t.selection.fireChanged();

Anti-pattern (laggy UI):

// BAD — fires N events.
for (const i of indices) t.selection.set(i, true);

From another BitSet

t.selection.copyFrom(other);     // replace
t.selection.or(other);           // add
t.selection.andNot(other);       // remove
t.selection.and(other);          // intersect

Clearing & inverting

// Deselect everything. setAll(FALSE), not TRUE.
t.selection.setAll(false);
// Flip the current selection.
t.selection.invert();

t.selection.setAll(true) selects every row — including rows currently hidden by the filter. For "select all currently-visible rows", copy from the filter (see below).

Selected rows as a new DataFrame

const subset = t.clone(t.selection);

Same shape as t.clone(t.filter) — different mask:

IdiomMask usedSource DF modified?
t.clone(t.filter)t.filterno — clone of visible rows
t.clone(t.selection)t.selectionno — clone of selected rows
// Open selected rows as a new table view.
const subset = t.clone(t.selection);
grok.shell.addTableView(subset);

If the selection is empty, clone returns a zero-row DataFrame (no error). Guard with t.selection.anyTrue first for user-facing flows.

Cross-skill bridges — selection ↔ filter

IdiomEffectPhrasing it answers
t.filter.copyFrom(t.selection)hide non-selected rows in place"show only", "filter to the selection"
t.selection.copyFrom(t.filter)mark every visible row as selected"select all currently-visible rows"

Critical disambiguation:

  • "select rows [by / where / top N]" → set t.selection via t.selection.init(pred) or index-list pattern.
  • "extract" / "copy" / "open as new table" / "give me a new table" → t.clone(t.selection) (new DataFrame; original unchanged).

t.selection.copyFrom(t.filter) fires onSelectionChanged but does NOT fire a filter event; the reverse holds for t.filter.copyFrom(t.selection).

Current row

// Focus row 5 (the platform usually does this on click; rarely needed in scripts).
if (5 >= 0 && 5 < t.rowCount)
  t.currentRowIdx = 5;

t.currentRow (a Row proxy) and t.currentCell (a Cell) follow currentRowIdx — read them on demand. Setting currentRowIdx = -1 is the valid "no current row" state.

Describing the current selection

No built-in "describe selection" — hand-roll a structured report: count, capped index list, sample row from the first selected index.

// Describe the current selection.
const sel = t.selection;
const all = sel.getSelectedIndexes();
const MAX_INDEXES = 50;
const MAX_SAMPLE_COLS = 12;
const indexes = Array.from(all.slice(0, MAX_INDEXES));

const out = {
  count: sel.trueCount,
  total: t.rowCount,
  indexes,
  currentRowIdx: t.currentRowIdx,
  sample: undefined,
};

if (all.length > 0) {
  const firstIdx = all[0];
  const cols = t.columns;
  const sample = {};
  const colCap = Math.min(cols.length, MAX_SAMPLE_COLS);
  for (let c = 0; c < colCap; c++) {
    const col = cols.byIndex(c);
    sample[col.name] = col.get(firstIdx);
  }
  out.sample = sample;
}
return out;

Selection event lifecycle

One event — unlike filter:

EventWhen
t.onSelectionChangedAny mutation on t.selection (set, init, setAll, and/or/xor/andNot, invert, copyFrom). Same observable as t.selection.onChanged.
// Log selection count whenever it changes.
const sub = t.onSelectionChanged.subscribe(() => {
  console.log(`selected: ${t.selection.trueCount}`);
});
view.subs.push(sub);

In a viewer / widget, push onto viewer.subs[] so the subscription cancels on detach (DG.Widget does this automatically).

Coalescing. Every BitSet mutator takes notify: boolean = true. Pass false in a loop and call fireChanged() once at the end:

for (let i = 0; i < indices.length; i++)
  t.selection.set(indices[i], true, false);  // notify = false
t.selection.fireChanged();                   // one coalesced event

Common patterns

// Toggle selection on a single row.
const i = 5;
t.selection.set(i, !t.selection.get(i));
// Top N by a column — sort, slice, set.
const idx = Array.from(t.getSortedOrder(['activity'], [false])).slice(0, 5);
t.selection.setAll(false, false);
for (const i of idx) t.selection.set(i, true, false);
t.selection.fireChanged();
// "Select what I see" → narrow → "filter to what I just selected" pipeline.
t.selection.copyFrom(t.filter);                                                // visible → selection
const flag = t.getCol('flag');
t.selection.and(DG.BitSet.create(t.rowCount, i => flag.get(i) === 'ok'));      // narrow
t.filter.copyFrom(t.selection);                                                // push back to filter

Anti-patterns

  1. t.selection.setAll(true) to "clear" the selection. That selects every row — the opposite of what filter's clear does. Use t.selection.setAll(false).
  2. t.filter.setAll(false) to "clear" the filter. Hides every row. Use t.filter.setAll(true). The cross-skill pair must be memorized together.
  3. t.rows.select(rowPred) for "replace selection" in perf-critical code. Functional, but iterates the RowList and per-bit set — materially slower than t.selection.init(pred), which is buffer-direct.
  4. t.selection.init(...) to add a condition to the selection. init zeros the buffer first. To extend, OR in DG.BitSet.create(t.rowCount, pred).
  5. Per-bit set in a loop without notify=false. N writes → N events → laggy UI. Always set(i, x, false) in the loop and fireChanged() at the end.
  6. t.selection.setAll(true) when the user means "select all visible". That includes filtered-out rows. Use t.selection.copyFrom(t.filter).
  7. Combining selections across DataFrames of different row counts. dfA.selection.and(dfB.selection) only makes sense if rows are aligned 1:1. Cross-table sync by key columns is grok.data.linkTables(...).
  8. t.rows.removeWhereIdx(pred) when asked to "remove from the selection". That deletes rows from the DF entirely. To narrow the selection, use andNot or set(i, false, false) in a loop.

Out of scope

  • Filter operations. t.filter lives in datagrok-filtering. Same BitSet API, opposite clear polarity — see the polarity table above.
  • Viewer-driven interactive selection. Lasso, grid click, shift-extend, ctrl-toggle — dispatched via BitSet.handleClick(rowPred, mouseEvent, ...). Covered by datagrok-viewers.
  • Cross-table selection sync. grok.data.linkTables(t1, t2, k1, k2, [SYNC_TYPE.SELECTION_TO_SELECTION, ...]) establishes long-lived sync.
  • Generic DataFrame cloning. For "copy of this DF with these columns" (no selection involved), see datagrok-df-and-columns.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Add support for a new curve data format in the Curves package converter system

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

datagrok-ai/public742026년 10월 20일 업데이트

Create info panels that appear in the context panel based on semantic types

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

datagrok-ai/public742026년 10월 20일 업데이트

Add a new single-objective optimization algorithm to the sci-comp library. Use when the user asks to implement a new optimizer (e.g. gradient descent, BFGS, simulated annealing, differential evolution).

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

datagrok-ai/public742026년 10월 20일 업데이트

Add unit tests to a Datagrok package

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

datagrok-ai/public742026년 10월 20일 업데이트

Answer a "how do I …" question about the platform with a Gherkin scenario on @datagrok-libraries/bdd that is filmed into a how-to video (grok-bdd guide), so the answer is demonstrated, sent as a video plus numbered steps, and kept as a regression test; the same scenarios, filmed in help mode, are the GIFs of the help pages

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

datagrok-ai/public742026년 10월 20일 업데이트

Translate hand-written Playwright specs (or any existing UI tests) into Gherkin features on @datagrok-libraries/bdd, then prove the features test what they claim by backward-matching them against the originals with independent reviewers, and fix the gaps in the core, the library and the features

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

datagrok-ai/public742026년 10월 20일 업데이트

datagrok-ai의 스킬 모두 보기

이 스킬의 문제 신고