Skip to content

DataTable: add summary statistics for selected cells#8326

Merged
mscolnick merged 26 commits intomarimo-team:mainfrom
andrewsoonqn:data-table-selection-stats
Feb 26, 2026
Merged

DataTable: add summary statistics for selected cells#8326
mscolnick merged 26 commits intomarimo-team:mainfrom
andrewsoonqn:data-table-selection-stats

Conversation

@andrewsoonqn
Copy link
Copy Markdown
Contributor

@andrewsoonqn andrewsoonqn commented Feb 16, 2026

📝 Summary

Closes #6015

Introduce summary statistics for selected cells to the data table component. When users select two or more cells, the UI now displays the count, sum, and average of the selected numeric values.

image

Demo:

cell-selection-data.mov

Works also with other components where DataTable is used, e.g., dataframes.

data-frame-selection-data.mov

🔍 Description of Changes

Decisions made:

  • Non-numeric data is included in Count only, and not included in calculation of Sum and Average
    • Empty cells, infinity, NaN, object, boolean, empty or practically empty (e.g. " ") strings are considered non-numeric
    • Numeric strings are considered numeric, e.g. the entry below shows up as a number in the table
    {"name": "Alice", "age": 30, "city": "New York", "balance": "100"},
image
  • The checkbox column to select rows is not included in any stats
  • Sum and Average are shown only when the selection contains at least one numeric value.
  • The CellSelectionStats component only shows when 2 or more cells are selected
  • Have a layout shift and add a new bottom row (like what search does when clicked)
  • Calculated stats are rounded to max 8 decimal points

Future considerations:

  • I have not implemented a way to disable this display. One suggestion is that we can add a context menu that can be used to check and uncheck stats to toggle their visibility.
  • Ability to copy stats by clicking on them.
  • More stats.

Implementation Details

  • Add a new CellSelectionStats component that displays the count, sum, and average of selected cells when two or more are selected.
  • Integrate CellSelectionStats into the DataTableInternal component, position is below the table. Wrap it in the CellSelectionProvider context.
  • Add a getNumericValuesFromSelectedCells utility function in utils.ts to extract numeric values from selected cells, filtering out non-numeric and special columns.

📋 Checklist

  • I have read the contributor guidelines.
  • For large changes, or changes that affect the public API: this change was discussed or approved through an issue, on Discord, or the community discussions (Please provide a link if applicable).
  • Tests have been added for the changes made.
  • Documentation has been updated where applicable, including docstrings for API changes.
  • Pull request title is a good summary of the changes - it will be used in the release notes.

@vercel
Copy link
Copy Markdown

vercel bot commented Feb 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Feb 25, 2026 7:34pm

Request Review

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds Excel-like summary statistics (Count, Sum, Average) to the DataTable component that appear when users select two or more cells. The feature filters numeric values intelligently, excluding non-numeric data from Sum and Average calculations while including all data cells in the Count. The statistics display is positioned below the table and only appears when multiple cells are selected.

Changes:

  • Added getNumericValuesFromSelectedCells and countDataCellsInSelection utility functions to extract and count cell data
  • Created CellSelectionStats component to display Count, Sum, and Average statistics
  • Moved CellSelectionProvider to wrap both the table and the new stats component, enabling state sharing

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
frontend/src/components/data-table/range-focus/utils.ts Added utility functions to count selected cells and extract numeric values, filtering out checkbox columns and non-numeric data
frontend/src/components/data-table/range-focus/cell-selection-stats.tsx New component displaying statistics (Count, Sum, Average) for selected cells with 8 decimal place rounding
frontend/src/components/data-table/range-focus/tests/utils.test.ts Added comprehensive tests for new utility functions and refactored existing test helpers into test-utils.ts
frontend/src/components/data-table/range-focus/tests/test-utils.ts Extracted reusable mock helper functions (createMockCell, createMockRow, createMockTable) for test consistency
frontend/src/components/data-table/range-focus/tests/cell-selection-stats.test.tsx Added thorough tests covering various scenarios: numeric/non-numeric values, rounding, checkbox exclusion, and edge cases
frontend/src/components/data-table/data-table.tsx Repositioned CellSelectionProvider to wrap both table and stats component, added CellSelectionStats below the table

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread frontend/src/components/data-table/range-focus/cell-selection-stats.tsx Outdated
Comment thread frontend/src/components/data-table/range-focus/utils.ts Outdated
@Light2Dark
Copy link
Copy Markdown
Collaborator

This looks really cool! Some of the team may be out (& I'm unwell), but happy to review soon.

Copy link
Copy Markdown
Collaborator

@Light2Dark Light2Dark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curious if you tried the other approaches (remove pagination / put in the middle at the bottom of the table)? How did it feel?

eg.
Image

Comment thread frontend/src/components/data-table/range-focus/cell-selection-stats.tsx Outdated
Comment thread frontend/src/components/data-table/range-focus/cell-selection-stats.tsx Outdated
Comment thread frontend/src/components/data-table/range-focus/utils.ts
continue;
}

const tableCell = row.getAllCells().find((c) => c.id === cellId);
Copy link
Copy Markdown
Collaborator

@Light2Dark Light2Dark Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this may be slightly unoptimized (I see it in old code too, and maybe we can replace it). The code below uses row.getValue instead of iterating through all the cells in a row.

export function getNumericValuesFromSelectedCells<TData>(
  table: Table<TData>,
  selectedCellIds: Set<string>,
): number[] {
  const numericValues: number[] = [];
  for (const cellId of selectedCellIds) {
    if (cellId.includes(SELECT_COLUMN_ID)) {
      continue;
    }
    const { rowId, columnId } = getRowAndColumnId(cellId);
    const row = table.getRow(rowId);
    if (!row) {
      continue;
    }

    const value = row.getValue(columnId);
    let num: number;
    if (typeof value === "number") {
      num = value;
    } else if (typeof value === "string") {
      if (value.trim() === "") {
        continue;
      }
      num = Number(value);
    } else {
      continue;
    }

    if (Number.isFinite(num)) {
      numericValues.push(num);
    }
  }
  return numericValues;
}

// at the end of the file
function getRowAndColumnId(cellId: string) {
  const sepIdx = cellId.indexOf("_");
  const rowId = cellId.slice(0, sepIdx);
  const columnId = cellId.slice(sepIdx + 1);
  return { rowId, columnId };
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix this along with the old code as well?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that would be good, you may need to update the tests as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we use this approach, it seems like there is no easy way to distinguish between missing cells and cells with value undefined. row.getValue(columnId) might return undefined both when the cell itself has value undefined. The tanstack table row also does not expose any methods like contains(columnId).

Do you have any suggestions? Was wondering whether a cell's value being undefined is possible in the first place, or will only empty cells have value of undefined?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think it's impossible to be undefined in the first place. I assume it would be undefined if columnId is incorrect, which shouldn't happen. I believe the test checks for this impossible scenario?

Copy link
Copy Markdown
Contributor Author

@andrewsoonqn andrewsoonqn Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Light2Dark Sorry havent got a chance to look at this yet. But last I checked, there was still some tests that failed in src/components/data-table/range-focus/__tests__/utils.test.ts related to null and undefined values. Will probably check those out by tomorrow.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah no worries, have fixed it for you. There were other CI failures as well so I jumped in.

@andrewsoonqn
Copy link
Copy Markdown
Contributor Author

curious if you tried the other approaches (remove pagination / put in the middle at the bottom of the table)? How did it feel?

@Light2Dark

  • Feels like putting in the middle will make the bottom a bit crowded.
  • Replacing pagination will make the user unable to navigate to other pages while having cells selected. This might be a minor inconvenience for some workflows. User needs to tap and unselect before they can switch pages.
  • Personal opinion is that it looks better as is. It feels more visually connected to the table, which makes sense given it's displaying stats about the table's data.
  • Feels like having it expand like this makes it more extensible in the future (more space)

Light2Dark
Light2Dark previously approved these changes Feb 25, 2026
Copy link
Copy Markdown
Collaborator

@Light2Dark Light2Dark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it looks good! Thank you :) The test failure seems unrelated.

Have adjusted the css to reduce the top padding

image

Use selectedCellsAtom to get size of cell selection and display.
Accordingly reorder components such that CellSelectionProvider's scope covers new CellSelectionStats component for it to use the selectedCellsAtom.
andrewsoonqn and others added 22 commits February 26, 2026 03:30
Add a new test-utils.ts exporting shared mock helpers (createMockCell, createMockColumn, createMockRow, createMockTable, createSelectedCell) and update utils.test.ts to import and use those helpers.
CellSelectionStats counts checkbox column on the left indicating whether a row is selected. This is counter-intuitive. Introduce utility to count all cells excluding the checkbox column.
…stats.tsx

Co-authored-by: Shahmir Varqha <Sham9871@gmail.com>
Getting values from selected cells uses iterating through all cells in a row.

Use row.getValue(columnId) instead for faster lookup.
@mscolnick mscolnick merged commit acfcd97 into marimo-team:main Feb 26, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Excel-like metrics with data table selection

4 participants