From 13e63cedf4566f60846b5682c86bd4385a9a2c19 Mon Sep 17 00:00:00 2001 From: Alexander Rose <alex.rose@rcsb.org> Date: Mon, 5 Mar 2018 18:33:33 -0800 Subject: [PATCH] added 'list' column type TODO handle in writer --- src/mol-data/db/_spec/table.spec.ts | 12 +++++++++++- src/mol-data/db/column.ts | 9 +++++++-- src/mol-io/reader/cif/binary/field.ts | 11 +++++++++-- src/mol-io/reader/cif/data-model.ts | 5 ++++- src/mol-io/reader/cif/schema.ts | 4 +++- src/mol-io/reader/cif/text/field.ts | 13 +++++++++++-- 6 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/mol-data/db/_spec/table.spec.ts b/src/mol-data/db/_spec/table.spec.ts index 51965938a..76aae4de0 100644 --- a/src/mol-data/db/_spec/table.spec.ts +++ b/src/mol-data/db/_spec/table.spec.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import * as ColumnHelpers from '../column-helpers' @@ -11,6 +12,8 @@ import Table from '../table' describe('column', () => { const cc = Column.ofConst(10, 2, Column.Schema.int); const arr = Column.ofArray({ array: [1, 2, 3, 4], schema: Column.Schema.int }); + const arrNumberList = Column.ofArray({ array: [[1, 2], [3, 4], [5, 6]], schema: Column.Schema.List<number>() }); + const arrStringList = Column.ofArray({ array: [['a', 'b'], ['c', 'd'], ['e', 'f']], schema: Column.Schema.List<string>() }); const arrWindow = Column.window(arr, 1, 3); const typed = Column.ofArray({ array: new Int32Array([1, 2, 3, 4]), schema: Column.Schema.int }); @@ -30,6 +33,13 @@ describe('column', () => { expect(arrWindow.rowCount).toBe(2); }); + it('arrList', () => { + expect(arrNumberList.rowCount).toBe(3); + expect(arrNumberList.value(1)).toEqual([3, 4]); + expect(arrStringList.rowCount).toBe(3); + expect(arrStringList.value(2)).toEqual(['e', 'f']); + }); + it('typed', () => { expect(typedWindow.value(0)).toBe(2); expect(typedWindow.rowCount).toBe(2); diff --git a/src/mol-data/db/column.ts b/src/mol-data/db/column.ts index d94afadcd..db692ef06 100644 --- a/src/mol-data/db/column.ts +++ b/src/mol-data/db/column.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import * as ColumnHelpers from './column-helpers' @@ -22,7 +23,7 @@ interface Column<T> { namespace Column { export type ArrayCtor<T> = { new(size: number): ArrayLike<T> } - export type Schema<T = any> = Schema.Str | Schema.Int | Schema.Float | Schema.Coordinate | Schema.Aliased<T> | Schema.Tensor + export type Schema<T = any> = Schema.Str | Schema.Int | Schema.Float | Schema.Coordinate | Schema.Aliased<T> | Schema.Tensor | Schema.List<number|string> export namespace Schema { // T also serves as a default value for undefined columns @@ -35,6 +36,7 @@ namespace Column { export type Tensor = { '@type': 'tensor', T: Tensors, space: Tensors.Space } & Base<'tensor'> export type Aliased<T> = { '@type': 'aliased', T: T } & Base<'str' | 'int'> + export type List<T extends number|string> = { '@type': 'list', T: T[] } & Base<'list'> export const str: Str = { '@type': 'str', T: '', valueType: 'str' }; export const int: Int = { '@type': 'int', T: 0, valueType: 'int' }; @@ -52,6 +54,9 @@ namespace Column { if (typeof defaultValue !== 'undefined') return { ...t, T: defaultValue } as any as Aliased<T>; return t as any as Aliased<T>; } + export function List<T extends number|string>(defaultValue: T[] = []): List<T> { + return { '@type': 'list', T: defaultValue, valueType: 'list' } + } } export interface ToArrayParams<T> { diff --git a/src/mol-io/reader/cif/binary/field.ts b/src/mol-io/reader/cif/binary/field.ts index c3b2ad33f..854eaa550 100644 --- a/src/mol-io/reader/cif/binary/field.ts +++ b/src/mol-io/reader/cif/binary/field.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { Column, ColumnHelpers } from 'mol-data/db' @@ -30,6 +31,10 @@ export default function Field(column: EncodedColumn): Data.Field { ? row => data[row] : row => { const v = data[row]; return fastParseFloat(v, 0, v.length); }; + const list: Data.Field['list'] = mask + ? row => mask[row] === Column.ValueKind.Present ? data[row] : [] + : row => data[row]; + const valueKind: Data.Field['valueKind'] = mask ? row => mask[row] : row => Column.ValueKind.Present; @@ -43,6 +48,7 @@ export default function Field(column: EncodedColumn): Data.Field { str, int, float, + list, valueKind, areValuesEqual: (rowA, rowB) => data[rowA] === data[rowB], toStringArray: params => ColumnHelpers.createAndFillArray(rowCount, str, params), @@ -51,6 +57,7 @@ export default function Field(column: EncodedColumn): Data.Field { : params => ColumnHelpers.createAndFillArray(rowCount, int, params), toFloatArray: isNumeric ? params => ColumnHelpers.typedArrayWindow(data, params) - : params => ColumnHelpers.createAndFillArray(rowCount, float, params) + : params => ColumnHelpers.createAndFillArray(rowCount, float, params), + toListArray: params => ColumnHelpers.createAndFillArray(rowCount, list, params) }; } \ No newline at end of file diff --git a/src/mol-io/reader/cif/data-model.ts b/src/mol-io/reader/cif/data-model.ts index 417692342..28299b659 100644 --- a/src/mol-io/reader/cif/data-model.ts +++ b/src/mol-io/reader/cif/data-model.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { Column } from 'mol-data/db' @@ -67,6 +68,7 @@ export interface Field { str(row: number): string, int(row: number): number, float(row: number): number, + list<T extends number|string>(row: number): T[], valueKind(row: number): Column.ValueKind, @@ -75,6 +77,7 @@ export interface Field { toStringArray(params?: Column.ToArrayParams<string>): ReadonlyArray<string>, toIntArray(params?: Column.ToArrayParams<number>): ReadonlyArray<number>, toFloatArray(params?: Column.ToArrayParams<number>): ReadonlyArray<number> + toListArray<T extends number|string>(params?: Column.ToArrayParams<T[]>): ReadonlyArray<T[]> } export function getTensor(category: Category, field: string, space: Tensor.Space, row: number): Tensor { diff --git a/src/mol-io/reader/cif/schema.ts b/src/mol-io/reader/cif/schema.ts index 1be7563d4..e3bb62f3e 100644 --- a/src/mol-io/reader/cif/schema.ts +++ b/src/mol-io/reader/cif/schema.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { Database, Table, Column, ColumnHelpers } from 'mol-data/db' @@ -23,6 +24,7 @@ function getColumnCtor(t: Column.Schema): ColumnCtor { case 'str': return (f, c, k) => createColumn(t, f, f.str, f.toStringArray); case 'int': return (f, c, k) => createColumn(t, f, f.int, f.toIntArray); case 'float': return (f, c, k) => createColumn(t, f, f.float, f.toFloatArray); + case 'list': return (f, c, k) => createColumn(t, f, f.list, f.toListArray); case 'tensor': throw new Error(`Use createTensorColumn instead.`); } } diff --git a/src/mol-io/reader/cif/text/field.ts b/src/mol-io/reader/cif/text/field.ts index 6d1888494..a1c929cba 100644 --- a/src/mol-io/reader/cif/text/field.ts +++ b/src/mol-io/reader/cif/text/field.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { Column, ColumnHelpers } from 'mol-data/db' @@ -27,6 +28,12 @@ export default function CifTextField(tokens: Tokens, rowCount: number): Data.Fie return fastParseFloat(data, indices[2 * row], indices[2 * row + 1]) || 0; }; + const list: Data.Field['list'] = <T extends string|number>(row: number) => { + const ret = data.substring(indices[2 * row], indices[2 * row + 1]); + if (ret === '.' || ret === '?') return []; + return ret.split(',') as T[]; + }; + const valueKind: Data.Field['valueKind'] = row => { const s = indices[2 * row]; if (indices[2 * row + 1] - s !== 1) return Column.ValueKind.Present; @@ -43,10 +50,12 @@ export default function CifTextField(tokens: Tokens, rowCount: number): Data.Fie str, int, float, + list, valueKind, areValuesEqual: TokenColumn.areValuesEqualProvider(tokens), toStringArray: params => ColumnHelpers.createAndFillArray(rowCount, str, params), toIntArray: params => ColumnHelpers.createAndFillArray(rowCount, int, params), - toFloatArray: params => ColumnHelpers.createAndFillArray(rowCount, float, params) + toFloatArray: params => ColumnHelpers.createAndFillArray(rowCount, float, params), + toListArray: params => ColumnHelpers.createAndFillArray(rowCount, list, params) } } \ No newline at end of file -- GitLab