@datagrok/bio
Advanced tools
Comparing version 1.7.22 to 1.7.23
@@ -5,3 +5,7 @@ { | ||
"friendlyName": "Bio", | ||
"version": "1.7.22", | ||
"author": { | ||
"name": "Leonid Stolbov", | ||
"email": "lstolbov@datagrok.ai" | ||
}, | ||
"version": "1.7.23", | ||
"description": "Bio is a [package](https://datagrok.ai/help/develop/develop#packages) for the [Datagrok](https://datagrok.ai) platform", | ||
@@ -15,3 +19,3 @@ "repository": { | ||
"@biowasm/aioli": ">=2.4.0", | ||
"@datagrok-libraries/bio": "^3.0.0", | ||
"@datagrok-libraries/bio": "^3.0.2", | ||
"@datagrok-libraries/ml": "^3.0.0", | ||
@@ -18,0 +22,0 @@ "@datagrok-libraries/utils": "^1.4.0", |
@@ -14,2 +14,3 @@ import * as DG from 'datagrok-api/dg'; | ||
import './tests/convert-test'; | ||
import './tests/fasta-handler-test'; | ||
import './tests/WebLogo-positions-test'; | ||
@@ -16,0 +17,0 @@ |
@@ -8,3 +8,3 @@ /* Do not change these import lines to match external modules in webpack configuration */ | ||
import {AlignedSequenceDifferenceCellRenderer, AminoAcidsCellRenderer} from './utils/cell-renderer'; | ||
import {MacromoleculeDifferenceCellRenderer, MonomerCellRenderer} from './utils/cell-renderer'; | ||
import {WebLogo, SeqColStats} from '@datagrok-libraries/bio/src/viewers/web-logo'; | ||
@@ -245,2 +245,10 @@ import {VdRegionsViewer} from './viewers/vd-regions-viewer'; | ||
//name: Bio | MSA | ||
//tags: bio, panel | ||
//input: column sequence { semType: Macromolecule } | ||
//output: column result | ||
export async function panelMSA(col: DG.Column): Promise<DG.Column | null> { | ||
return multipleSequenceAlignmentAny(col.dataFrame, col); | ||
} | ||
//name: Composition Analysis | ||
@@ -339,16 +347,16 @@ //top-menu: Bio | Composition Analysis | ||
//name: aminoAcidsCellRenderer | ||
//name: monomerCellRenderer | ||
//tags: cellRenderer | ||
//meta.cellType: aminoAcids | ||
//meta.cellType: Monomer | ||
//output: grid_cell_renderer result | ||
export function aminoAcidsCellRenderer(): AminoAcidsCellRenderer { | ||
return new AminoAcidsCellRenderer(); | ||
export function monomerCellRenderer(): MonomerCellRenderer { | ||
return new MonomerCellRenderer(); | ||
} | ||
//name: alignedSequenceDifferenceCellRenderer | ||
//name: MacromoleculeDifferenceCellRenderer | ||
//tags: cellRenderer | ||
//meta.cellType: alignedSequenceDifference | ||
//meta.cellType: MacromoleculeDifference | ||
//output: grid_cell_renderer result | ||
export function alignedSequenceDifferenceCellRenderer(): AlignedSequenceDifferenceCellRenderer { | ||
return new AlignedSequenceDifferenceCellRenderer(); | ||
export function macromoleculeDifferenceCellRenderer(): MacromoleculeDifferenceCellRenderer { | ||
return new MacromoleculeDifferenceCellRenderer(); | ||
} | ||
@@ -355,0 +363,0 @@ |
@@ -0,1 +1,2 @@ | ||
import {after, before, category, test, expect, expectObject} from '@datagrok-libraries/utils/src/test'; | ||
@@ -7,6 +8,6 @@ | ||
import {PositionInfo, PositionMonomerInfo, WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo'; | ||
category('WebLogo-positions', () => { | ||
let tvList: DG.TableView[]; | ||
let dfList: DG.DataFrame[]; | ||
let currentView: DG.View; | ||
@@ -26,9 +27,10 @@ const csvDf1 = `seq | ||
dfList = []; | ||
currentView = grok.shell.tv; | ||
}); | ||
after(async () => { | ||
dfList.forEach((df: DG.DataFrame) => { grok.shell.closeTable(df); }); | ||
dfList.forEach((df: DG.DataFrame) => { grok.shell.closeTable(df);}); | ||
tvList.forEach((tv: DG.TableView) => tv.close()); | ||
currentView = grok.shell.tv; | ||
}); | ||
test('allPositions', async () => { | ||
@@ -60,12 +62,82 @@ const df: DG.DataFrame = DG.DataFrame.fromCsv(csvDf1); | ||
]; | ||
console.log(positions); | ||
expect(positions.length,resAllDf1.length); | ||
// check all positions are equal resAllDf1 | ||
for (let i = 0; i < positions.length; i++) { | ||
expect(positions[i].name, resAllDf1[i].name); | ||
for (const key in positions[i].freq) { | ||
expect(positions[i].freq[key].count, resAllDf1[i].freq[key].count); | ||
} | ||
for (const key in positions[i].freq) { | ||
expect(positions[i].freq[key].count, resAllDf1[i].freq[key].count); | ||
} | ||
} | ||
}); | ||
test('positions with shrinkEmptyTail option', async () => { | ||
const df: DG.DataFrame = DG.DataFrame.fromCsv(csvDf1); | ||
const tv: DG.TableView = grok.shell.addTableView(df); | ||
const wlViewer: WebLogo = await df.plot.fromType('WebLogo', {'shrinkEmptyTail': true}) as unknown as WebLogo; | ||
tv.dockManager.dock(wlViewer.root, DG.DOCK_TYPE.DOWN); | ||
tvList.push(tv); | ||
dfList.push(df); | ||
const positions: PositionInfo[] = wlViewer['positions']; | ||
const resAllDf1: PositionInfo[] = [ | ||
new PositionInfo('1', {'A': new PositionMonomerInfo(2), '-': new PositionMonomerInfo(3)}), | ||
new PositionInfo('2', {'T': new PositionMonomerInfo(5)}), | ||
new PositionInfo('3', {'C': new PositionMonomerInfo(5)}), | ||
new PositionInfo('4', {'-': new PositionMonomerInfo(5)}), | ||
new PositionInfo('5', {'G': new PositionMonomerInfo(5)}), | ||
new PositionInfo('6', {'-': new PositionMonomerInfo(3), 'C': new PositionMonomerInfo(2)}), | ||
new PositionInfo('7', {'T': new PositionMonomerInfo(5)}), | ||
new PositionInfo('8', {'T': new PositionMonomerInfo(5)}), | ||
new PositionInfo('9', {'G': new PositionMonomerInfo(5)}), | ||
new PositionInfo('10', {'C': new PositionMonomerInfo(5)}) | ||
]; | ||
console.log(positions); | ||
for (let i = 0; i < positions.length; i++) { | ||
expect(positions[i].name, resAllDf1[i].name); | ||
for (const key in positions[i].freq) { | ||
expect(positions[i].freq[key].count, resAllDf1[i].freq[key].count); | ||
} | ||
} | ||
}); | ||
test('positions with skipEmptyPositions option', async () => { | ||
const df: DG.DataFrame = DG.DataFrame.fromCsv(csvDf1); | ||
const tv: DG.TableView = grok.shell.addTableView(df); | ||
const wlViewer: WebLogo = await df.plot.fromType('WebLogo', {'skipEmptyPositions': false}) as unknown as WebLogo; | ||
tv.dockManager.dock(wlViewer.root, DG.DOCK_TYPE.DOWN); | ||
tvList.push(tv); | ||
dfList.push(df); | ||
const positions: PositionInfo[] = wlViewer['positions']; | ||
const resAllDf1: PositionInfo[] = [ | ||
new PositionInfo('1', {'A': new PositionMonomerInfo(2), '-': new PositionMonomerInfo(3)}), | ||
new PositionInfo('2', {'T': new PositionMonomerInfo(5)}), | ||
new PositionInfo('3', {'C': new PositionMonomerInfo(5)}), | ||
new PositionInfo('5', {'G': new PositionMonomerInfo(5)}), | ||
new PositionInfo('6', {'-': new PositionMonomerInfo(3), 'C': new PositionMonomerInfo(2)}), | ||
new PositionInfo('7', {'T': new PositionMonomerInfo(5)}), | ||
new PositionInfo('8', {'T': new PositionMonomerInfo(5)}), | ||
new PositionInfo('9', {'G': new PositionMonomerInfo(5)}), | ||
new PositionInfo('10', {'C': new PositionMonomerInfo(5)}) | ||
]; | ||
console.log(positions); | ||
for (let i = 0; i < positions.length; i++) { | ||
expect(positions[i].name, resAllDf1[i].name); | ||
for (const key in positions[i].freq) { | ||
expect(positions[i].freq[key].count, resAllDf1[i].freq[key].count); | ||
} | ||
} | ||
}); | ||
}); |
@@ -149,1 +149,2 @@ import {after, before, category, test, expect, expectObject} from '@datagrok-libraries/utils/src/test'; | ||
} | ||
@@ -5,3 +5,3 @@ import * as C from './constants'; | ||
import {NucleotidesPalettes} from '@datagrok-libraries/bio/src/nucleotides'; | ||
import {UnknownSeqPalettes} from '@datagrok-libraries/bio/src/unknown'; | ||
import {UnknownSeqPalette, UnknownSeqPalettes} from '@datagrok-libraries/bio/src/unknown'; | ||
import {SplitterFunc, WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo'; | ||
@@ -48,2 +48,3 @@ import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes'; | ||
/** | ||
@@ -70,12 +71,24 @@ * A function that prints a string aligned to left or centered. | ||
pivot: number = 0, left = false, transparencyRate: number = 1.0, | ||
separator: string = '', last: boolean = false): number { | ||
separator: string = '', last: boolean = false, drawStyle: string = 'classic', maxWord:any={}, maxWordIdx:number=0, gridCell:any = {}): number { | ||
g.textAlign = 'start'; | ||
const colorPart = s.substring(0); | ||
let grayPart = last ? '' : separator; | ||
let grayPart = last ? '' : separator; | ||
if (drawStyle === 'msa') { | ||
grayPart = ' '; | ||
} | ||
const textSize = g.measureText(colorPart + grayPart); | ||
let textSize: any = g.measureText(colorPart + grayPart); | ||
const indent = 5; | ||
const colorTextSize = g.measureText(colorPart); | ||
let colorTextSize = g.measureText(colorPart).width; | ||
const dy = (textSize.fontBoundingBoxAscent + textSize.fontBoundingBoxDescent) / 2; | ||
textSize = textSize.width; | ||
if (drawStyle === 'msa') { | ||
if (colorTextSize > maxWord) { | ||
maxWord[maxWordIdx] = colorTextSize; | ||
gridCell.cell.column.temp = maxWord; | ||
} | ||
colorTextSize = maxWord[maxWordIdx]; | ||
textSize = maxWord[maxWordIdx]; | ||
} | ||
@@ -86,14 +99,15 @@ function draw(dx1: number, dx2: number): void { | ||
g.fillText(colorPart, x + dx1, y + dy); | ||
g.fillStyle = grayColor; | ||
g.fillText(grayPart, x + dx2, y + dy); | ||
if (drawStyle === 'classic') { | ||
g.fillStyle = grayColor; | ||
g.fillText(grayPart, x + dx2, y + dy); | ||
} | ||
} | ||
if (left || textSize.width > w) { | ||
draw(indent, indent + colorTextSize.width); | ||
return x + colorTextSize.width + g.measureText(grayPart).width; | ||
if (left || textSize > w) { | ||
draw(indent, indent + colorTextSize); | ||
return x + colorTextSize + g.measureText(grayPart).width; | ||
} else { | ||
const dx = (w - textSize.width) / 2; | ||
draw(dx, dx + colorTextSize.width); | ||
return x + dx + colorTextSize.width; | ||
const dx = (w - textSize) / 2; | ||
draw(dx, dx + colorTextSize); | ||
return x + dx + colorTextSize; | ||
} | ||
@@ -121,3 +135,3 @@ } | ||
get cellType(): string { return C.SEM_TYPES.Macro_Molecule; } | ||
get cellType(): string { return C.SEM_TYPES.MACROMOLECULE; } | ||
@@ -206,6 +220,42 @@ get defaultHeight(): number { return 30; } | ||
// обработка новых елементов | ||
const columns = gridCell.cell.column.categories; | ||
let maxLengthWords = {}; | ||
// check if gridCell.cell.column.temp is array | ||
if (gridCell.cell.column.getTag('.calculatedCellRender') !== 'exist') { | ||
for (let i = 0; i < columns.length; i++) { | ||
let subParts: string[] = splitterFunc(columns[i]); | ||
subParts.forEach((amino, index) => { | ||
//@ts-ignore | ||
let textSizeWidth = g.measureText(WebLogo.monomerToText(amino) + ' '); | ||
//@ts-ignore | ||
if (textSizeWidth.width > (maxLengthWords[index] ?? 0)) { | ||
//@ts-ignore | ||
maxLengthWords[index] = textSizeWidth.width; | ||
} | ||
}); | ||
} | ||
gridCell.cell.column.temp = maxLengthWords; | ||
gridCell.cell.column.setTag('.calculatedCellRender', 'exist'); | ||
} else { | ||
maxLengthWords = gridCell.cell.column.temp; | ||
} | ||
const subParts: string[] = splitterFunc(cell.value); | ||
// console.log(subParts); | ||
let x1 = x; | ||
let color = undefinedColor; | ||
// get max length word in subParts | ||
let tagUnits = gridCell.cell.column.getTag(DG.TAGS.UNITS); | ||
let maxLength = 0; | ||
let maxWord = ''; | ||
let drawStyle = 'classic'; | ||
if (tagUnits.includes('MSA')) { | ||
subParts.forEach(part => { | ||
if (part.length > maxLength) { | ||
maxLength = part.length; | ||
maxWord = part; | ||
drawStyle = 'msa'; | ||
} | ||
}); | ||
} | ||
subParts.forEach((amino, index) => { | ||
@@ -215,3 +265,3 @@ color = palette.get(amino); | ||
let last = index === subParts.length - 1; | ||
x1 = printLeftOrCentered(x1, y, w, h, g, amino, color, 0, true, 1.0, separator, last); | ||
x1 = printLeftOrCentered(x1, y, w, h, g, WebLogo.monomerToText(amino), color, 0, true, 1.0, separator, last, drawStyle, maxLengthWords, index, gridCell); | ||
}); | ||
@@ -225,8 +275,7 @@ | ||
export class MonomerCellRenderer extends DG.GridCellRenderer { | ||
get name(): string {return 'MonomerCR';} | ||
export class AminoAcidsCellRenderer extends DG.GridCellRenderer { | ||
get name(): string {return 'aminoAcidsCR';} | ||
get cellType(): string {return C.SEM_TYPES.MONOMER;} | ||
get cellType(): string {return C.SEM_TYPES.AMINO_ACIDS;} | ||
get defaultHeight(): number {return 15;} | ||
@@ -267,6 +316,6 @@ | ||
export class AlignedSequenceDifferenceCellRenderer extends DG.GridCellRenderer { | ||
get name(): string {return 'alignedSequenceDifferenceCR';} | ||
export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer { | ||
get name(): string {return 'MacromoleculeDifferenceCR';} | ||
get cellType(): string {return C.SEM_TYPES.ALIGNED_SEQUENCE_DIFFERENCE;} | ||
get cellType(): string {return C.SEM_TYPES.MACROMOLECULE_DIFFERENCE;} | ||
@@ -307,4 +356,6 @@ get defaultHeight(): number {return 30;} | ||
const separator = gridCell.tableColumn!.tags[C.TAGS.SEPARATOR]; | ||
const subParts1 = s1.split(separator); | ||
const subParts2 = s2.split(separator); | ||
const units: string = gridCell.tableColumn!.tags[DG.TAGS.UNITS]; | ||
const splitter = WebLogo.getSplitter(units, separator); | ||
const subParts1 = splitter(s1); | ||
const subParts2 = splitter(s2); | ||
const [text] = processSequence(subParts1); | ||
@@ -316,3 +367,7 @@ const textSize = g.measureText(text.join('')); | ||
const palette = getPalleteByType(gridCell.tableColumn!.tags[C.TAGS.ALPHABET]); | ||
let palette: SeqPalette = UnknownSeqPalettes.Color; | ||
if (units != 'HELM') | ||
palette = getPalleteByType(units.substring(units.length - 2)); | ||
const vShift = 7; | ||
for (let i = 0; i < subParts1.length; i++) { | ||
@@ -322,6 +377,5 @@ const amino1 = subParts1[i]; | ||
const color1 = palette.get(amino1); | ||
const color2 = palette.get(amino2); | ||
if (amino1 != amino2) { | ||
const vShift = 7; | ||
const color2 = palette.get(amino2); | ||
const subX0 = printLeftOrCentered(updatedX, updatedY - vShift, w, h, g, amino1, color1, 0, true); | ||
@@ -328,0 +382,0 @@ const subX1 = printLeftOrCentered(updatedX, updatedY + vShift, w, h, g, amino2, color2, 0, true); |
@@ -26,8 +26,7 @@ export enum COLUMNS_NAMES { | ||
export enum SEM_TYPES { | ||
AMINO_ACIDS = 'aminoAcids', | ||
ALIGNED_SEQUENCE = 'alignedSequence', | ||
ALIGNED_SEQUENCE_DIFFERENCE = 'alignedSequenceDifference', | ||
MONOMER = 'Monomer', | ||
MACROMOLECULE_DIFFERENCE = 'MacromoleculeDifference', | ||
ACTIVITY = 'activity', | ||
ACTIVITY_SCALED = 'activityScaled', | ||
Macro_Molecule = 'Macromolecule', | ||
MACROMOLECULE = 'Macromolecule', | ||
} | ||
@@ -34,0 +33,0 @@ |
@@ -53,2 +53,5 @@ import * as ui from 'datagrok-api/ui'; | ||
public skipEmptyPositions: boolean; | ||
public get df(): DG.DataFrame { | ||
@@ -76,2 +79,4 @@ return this.dataFrame; | ||
this.sequenceColumnNamePostfix = this.string('sequenceColumnNamePostfix', 'chain sequence'); | ||
this.skipEmptyPositions = this.bool('skipEmptyPositions', false); | ||
} | ||
@@ -124,2 +129,13 @@ | ||
break; | ||
case 'skipEmptyPositions': | ||
// for (let orderI = 0; orderI < this.logos.length; orderI++) { | ||
// for (let chainI = 0; chainI < this.chains.length; chainI++) { | ||
// const chain: string = this.chains[chainI]; | ||
// this.logos[orderI][chain].setOptions({skipEmptyPositions: this.skipEmptyPositions}); | ||
// } | ||
// } | ||
// this.calcSize(); | ||
await this.destroyView(); | ||
await this.buildView(); | ||
break; | ||
} | ||
@@ -194,2 +210,3 @@ } | ||
fixWidth: true, | ||
skipEmptyPositions: this.skipEmptyPositions, | ||
})) as unknown as WebLogo; | ||
@@ -196,0 +213,0 @@ } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
14187049
84
99592
1