Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
64 changes: 64 additions & 0 deletions docs/source/_static/js/sortable-numeric.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* sortable-numeric.js
*
* DataTables custom column type: "num-varies".
*
* The paradigm summary tables on dataset_summary.html are made sortable by a
* single shared `$('.sortable').DataTable()` call with no per-column config, so
* DataTables has to auto-detect each column's type. Its numeric detector is
* all-or-nothing: one non-numeric cell downgrades the whole column to string
* (lexicographic) sorting. Several numeric columns ("Total_trials",
* "#Trials / class", "#Runs") carry the sentinel "varies" for datasets whose
* trial count is not fixed, which silently broke numeric sorting for them
* (e.g. Total_trials ordered 11000, 1114, 11496, 1200, ...).
*
* This plugin registers a column type that treats a column as numeric when
* every cell is EITHER a number OR a known sentinel, ordering the sentinel
* rows as -Infinity so they sink to the bottom of a largest-first sort while
* still DISPLAYING their original text ("varies") to the reader.
*/
(function () {
"use strict";

var DataTable = jQuery.fn.dataTable;

// Tokens that stand in for "no single numeric value". Matched case-folded and
// trimmed; the empty string counts too, so one blank cell can't silently
// re-trigger the string-sort bug.
var SENTINELS = ["varies", "n/a", "na", "-", "—", ""];

// Strip any HTML DataTables may hand us and normalise for comparison.
function clean(value) {
return String(value).replace(/<[^>]*>/g, "").trim();
}

function isSentinel(text) {
return SENTINELS.indexOf(text.toLowerCase()) !== -1;
}

function asNumber(text) {
return parseFloat(text.replace(/,/g, ""));
}

DataTable.type("num-varies", {
// Claim a column only if EVERY cell is a number or a known sentinel.
// A named custom type is always checked before the built-in "string"
// fallback, so a mixed number/"varies" column lands here rather than being
// sorted lexicographically.
detect: function (value) {
var text = clean(value);
return isSentinel(text) || !isNaN(asNumber(text));
},
// Ordering key: real numbers sort normally; sentinels pin to the bottom.
order: {
pre: function (value) {
var text = clean(value);
if (isSentinel(text)) {
return -Infinity;
}
var n = asNumber(text);
return isNaN(n) ? -Infinity : n;
},
},
});
})();
3 changes: 3 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,9 @@ def linkcode_resolve(domain, info): # noqa: C901
"https://cdn.datatables.net/searchpanes/2.3.5/js/searchPanes.dataTables.js",
# FixedHeader (sticky header on scroll)
"https://cdn.datatables.net/fixedheader/4.0.6/js/dataTables.fixedHeader.js",
# Custom "num-varies" column type: numeric sort for columns that mix numbers
# with the "varies" sentinel (used by the .sortable paradigm tables).
"js/sortable-numeric.js",
"js/section-nav-hierarchy.js",
"js/macro-table.js",
]
Expand Down
2 changes: 2 additions & 0 deletions docs/source/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ Bugs
- Fix missing electrode positions (NaN xyz) in six motor-imagery datasets so topographic maps, interpolation, and spatial methods work: :class:`moabb.datasets.Forenzo2023` and :class:`moabb.datasets.GuttmannFlury2025_MI`/``_ME`` normalize Neuroscan ALL_CAPS labels and apply ``standard_1005`` (CB1/CB2 kept as ``misc``); :class:`moabb.datasets.Dreyer2023` falls back to ``standard_1005`` when the BIDS archive ships no ``electrodes.tsv``; :class:`moabb.datasets.BNCI2003_004` maps its 26 legacy Berlin channel labels to their modern 10-5 equivalents for exact positions; :class:`moabb.datasets.BNCI2014_002` applies an approximate 3x5 grid for its unlabeled small-Laplacian channels; and :class:`moabb.datasets.Zhang2017` applies the ``GSN-HydroCel-32`` montage in EGI sensor order. Adds the shared :func:`moabb.datasets.utils.set_neuroscan_montage` helper (:gh:`1089` by `Bruno Aristimunha`_).
- Fix ``BaseEvaluation._aggregate_fold_results`` aborting the whole evaluation with ``TypeError: agg function failed [how->mean,dtype->object]`` when a single fold contributes a non-numeric ``score`` (e.g. an error fold). The numeric aggregation columns are now coerced with ``pandas.to_numeric(errors="coerce")`` before ``groupby.agg``, so a bad fold becomes ``NaN`` and is skipped instead of taking down every subject/pipeline (:gh:`1095` by `Bruno Aristimunha`_).
- Fix :class:`moabb.evaluations.splitters.WithinSessionSplitter` and :class:`moabb.evaluations.splitters.WithinSubjectSplitter` overwriting an explicit ``n_splits`` passed through ``cv_kwargs`` with the ``n_folds`` default; the caller-provided ``n_splits`` now takes precedence, so a single holdout split can be requested directly via ``cv_class=StratifiedShuffleSplit, n_splits=1``. :class:`moabb.evaluations.WithinSessionEvaluation` and :class:`moabb.evaluations.WithinSubjectEvaluation` now honour the ``n_splits`` argument instead of always running 5 folds, and :class:`moabb.evaluations.splitters.WithinSubjectSplitter` now yields reproducible per-subject folds for a fixed ``random_state`` (:gh:`1106` by `Bruno Aristimunha`_).
- Fix numeric sorting in the dataset summary tables (:doc:`dataset_summary`): columns containing the ``varies`` sentinel (e.g. ``Total_trials``) were auto-detected as strings by DataTables and sorted lexicographically (``11000 < 1114 < 11496``). A custom ``num-varies`` column type now treats such columns as numeric, sorting sentinel rows last while keeping their displayed text unchanged (:gh:`1118` by `Bhargav Kowshik`_).

Code health
~~~~~~~~~~~
- Install CPU-only PyTorch wheels in CI by setting ``UV_TORCH_BACKEND=cpu`` in the test, braindecode, and docs workflows, so runners no longer download multi-GB CUDA builds of ``torch`` (pulled transitively via the ``deeplearning`` extra / braindecode) (:gh:`1083` by `Bhargav Kowshik`_).
Expand Down
Loading