mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-25 14:58:12 +08:00
Experimental - manual annotations (#837)
* icons, partway * redux for values * onChange * cancel * annotations lifecycle for category names * copy categorical * edit category * add Dataframe.withColsFrom * render user annotations; default add/delete annotation category * add label name to actions * category name edit * error checking improvements * change schema field isUserAnnotation to writable * always have an unassigned label; implement delete label * implement add new label and edit label name * label current cell selection * fix select exact bug in crossfilter * clean up categorical reducer * fix tests * remove debugging printf * implement subset/reset for user annotations * undo redo support for user annotations * remove duplicate button from categories * add modal * remove obsolete duplicate annotation reducers * remove old debugging printf * connect modal to annotation create and dup * initial full-stack wiring * finish up end-to-end wiring * fix existing unit tests * fix pytests to match new schema API * remove debugging printfs * add label file rotation * remove obsolete comment * add fbs encode/decode tests * add tests for writable annotations * simplify code * fix hashing bug with FBS encoding * lint * fix smoke tests * improve error checking in Dataframe.withColsFrom * add unit test for Dataframe.withColsFrom * add unit test for Dataframe.columns and Dataframe.renameCol * fix bug in FBS encode, add better error checks, refactor * add FBS encode/decode test * add clarifying comment * clean up action type names; fix state inconsistency in crossfilter update * change autosave timer to 2.5sec * sort categorical metadata render order so it remains consistent * add temporary autogenerated label for add-new-label operation * fix hover-over label menu interference with cell highlighting * remove debugging code * add missing reducer cases & fix typo * make dataframe memoize more general purpose * add dev mode for annos * fix error on select duplicate * handle zero occupancy categories * correctly maintain unclipped AND clipped world * correctly handle zero length FBS matrix and label files * ensure all writable categorical schema contains an unassigned category * handle case where building occupancy stack for category with no members * dialog for creating label, disable button if duplicate or empty * visually separate writeable * edit category * fix edit category name * remove debugging code * fix edit annotation label * visually define unassigned, change options * Pull in requirements.txt from `master` * label currently selected cells * duplicate label * lint * fix pytest merge issues * rename --label-file to --experimental-label-file * remove debugging console log * spelling error fix; fix bug found in PR review. * lint
This commit is contained in:
committed by
Colin Megill
parent
ab2c423006
commit
3660a6cc27
@@ -345,12 +345,50 @@ class Dataframe {
|
||||
);
|
||||
}
|
||||
|
||||
withColsFrom(dataframe) {
|
||||
/*
|
||||
return a new dataframe containing all columns from both `this` and the
|
||||
provided dataframe.
|
||||
|
||||
The row index from `this` will be used. Both dataframes must have identical
|
||||
dimensionality, and no overlapping columns labels.
|
||||
*/
|
||||
const dims = [this.dims[0], this.dims[1] + dataframe.dims[1]];
|
||||
const { rowIndex } = this;
|
||||
const columns = [...this.__columns, ...dataframe.__columns];
|
||||
const colIndex = this.colIndex.withLabels(dataframe.colIndex.keys());
|
||||
const columnsAccessor = [
|
||||
...this.__columnsAccessor,
|
||||
...dataframe.__columnsAccessor
|
||||
];
|
||||
return new this.constructor(
|
||||
dims,
|
||||
columns,
|
||||
rowIndex,
|
||||
colIndex,
|
||||
columnsAccessor
|
||||
);
|
||||
}
|
||||
|
||||
dropCol(label) {
|
||||
/*
|
||||
Create a new dataframe, omitting one columns.
|
||||
|
||||
const newDf = df.dropCol("colors");
|
||||
|
||||
Corner case to manage: if dropping the last column, return an empty dataframe.
|
||||
*/
|
||||
if (!this.hasCol(label)) {
|
||||
throw new RangeError(`unknown label: ${label}`);
|
||||
}
|
||||
|
||||
/*
|
||||
Corner case to manage: if dropping the last column, return an empty dataframe.
|
||||
*/
|
||||
if (this.dims[1] === 1) {
|
||||
return Dataframe.empty();
|
||||
}
|
||||
|
||||
const dims = [this.dims[0], this.dims[1] - 1];
|
||||
const coffset = this.colIndex.getOffset(label);
|
||||
const columns = [...this.__columns];
|
||||
@@ -367,6 +405,50 @@ class Dataframe {
|
||||
);
|
||||
}
|
||||
|
||||
renameCol(oldLabel, newLabel) {
|
||||
/*
|
||||
Accelerator for dropping a column and then adding it again with a new label
|
||||
*/
|
||||
const coffset = this.colIndex.getOffset(oldLabel);
|
||||
const colIndex = this.colIndex.dropLabel(oldLabel).withLabel(newLabel);
|
||||
|
||||
const columns = [...this.__columns];
|
||||
columns.push(columns[coffset]);
|
||||
columns.splice(coffset, 1);
|
||||
|
||||
const columnsAccessor = [...this.__columnsAccessor];
|
||||
columnsAccessor.push(columnsAccessor[coffset]);
|
||||
columnsAccessor.splice(coffset, 1);
|
||||
|
||||
return new this.constructor(
|
||||
this.dims,
|
||||
columns,
|
||||
this.rowIndex,
|
||||
colIndex,
|
||||
columnsAccessor
|
||||
);
|
||||
}
|
||||
|
||||
replaceColData(label, newColData) {
|
||||
/*
|
||||
Accelerator for dropping a column then adding it again with same
|
||||
label and different values.
|
||||
*/
|
||||
const coffset = this.colIndex.getOffset(label);
|
||||
const columns = [...this.__columns];
|
||||
columns[coffset] = newColData;
|
||||
const columnsAccessor = [...this.__columnsAccessor];
|
||||
columnsAccessor[coffset] = null;
|
||||
|
||||
return new this.constructor(
|
||||
this.dims,
|
||||
columns,
|
||||
this.rowIndex,
|
||||
this.colIndex,
|
||||
columnsAccessor
|
||||
);
|
||||
}
|
||||
|
||||
static empty(rowIndex = null, colIndex = null) {
|
||||
return new Dataframe([0, 0], [], rowIndex, colIndex);
|
||||
}
|
||||
@@ -443,6 +525,8 @@ class Dataframe {
|
||||
return newCol;
|
||||
});
|
||||
}
|
||||
|
||||
if (dims[0] === 0 || dims[1] === 0) return Dataframe.empty();
|
||||
return new Dataframe(dims, columns, rowIndex, colIndex);
|
||||
}
|
||||
|
||||
@@ -526,6 +610,11 @@ class Dataframe {
|
||||
Data access with row/col.
|
||||
**/
|
||||
|
||||
columns() {
|
||||
/* return all column accessors as an array, in offset order */
|
||||
return [...this.__columnsAccessor];
|
||||
}
|
||||
|
||||
col(columnLabel) {
|
||||
/*
|
||||
Return accessor bound to a column. Allows random row access
|
||||
|
||||
Reference in New Issue
Block a user