diff --git a/angular.json b/angular.json
index d63e535..893400c 100644
--- a/angular.json
+++ b/angular.json
@@ -217,12 +217,12 @@
"configurations": {
"production": {
"tsConfig": "projects/ngx-sequence-viewer/tsconfig.lib.prod.json"
- },
+ },
"development": {
"tsConfig": "projects/ngx-sequence-viewer/tsconfig.lib.json"
}
},
- "defaultConfiguration": "production"
+ "defaultConfiguration": "development"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
diff --git a/projects/ngx-sequence-viewer/package.json b/projects/ngx-sequence-viewer/package.json
index 069fc05..0b5ad02 100644
--- a/projects/ngx-sequence-viewer/package.json
+++ b/projects/ngx-sequence-viewer/package.json
@@ -1,6 +1,6 @@
{
"name": "ngx-sequence-viewer",
- "version": "0.0.6",
+ "version": "0.0.9",
"peerDependencies": {
"@angular/common": "^17.3.0",
"@angular/core": "^17.3.0"
diff --git a/projects/utils/fasta.spec.ts b/projects/ngx-sequence-viewer/src/lib/colors.spec.ts
similarity index 100%
rename from projects/utils/fasta.spec.ts
rename to projects/ngx-sequence-viewer/src/lib/colors.spec.ts
diff --git a/projects/ngx-sequence-viewer/src/lib/ngx-sequence-viewer.component.html b/projects/ngx-sequence-viewer/src/lib/ngx-sequence-viewer.component.html
index 8c96ff6..d78f34c 100644
--- a/projects/ngx-sequence-viewer/src/lib/ngx-sequence-viewer.component.html
+++ b/projects/ngx-sequence-viewer/src/lib/ngx-sequence-viewer.component.html
@@ -9,7 +9,7 @@
Index
- @if(sequences.length > 1) {
+ @if(sequences!.length > 1) {
Consensus
}
@@ -30,7 +30,7 @@
- @if(sequences.length > 1) {
+ @if(sequences!.length > 1) {
}
@@ -81,7 +81,7 @@
[style.color]="style['color']"
(mouseenter)="onMouseEnter($event, indexService.keys[j])"
(mousedown)="onMouseDown($event, indexService.keys[j])">
- {{ value ? value : sequences[i][j] }}
+ {{ value ? value : sequences![i][j] }}
}
}
diff --git a/projects/ngx-sequence-viewer/src/lib/ngx-sequence-viewer.component.ts b/projects/ngx-sequence-viewer/src/lib/ngx-sequence-viewer.component.ts
index 7c61d90..504f8b5 100644
--- a/projects/ngx-sequence-viewer/src/lib/ngx-sequence-viewer.component.ts
+++ b/projects/ngx-sequence-viewer/src/lib/ngx-sequence-viewer.component.ts
@@ -7,7 +7,7 @@ import { CommonModule } from '@angular/common';
import { ColorMap, ZAPPO } from './colors';
import { SelectionService } from './services/selection.service';
import { IndexService } from './services/index.service';
-import { parseFasta } from './utils';
+import { FASTA } from './utils';
// export interface Locus {
// // Define start position (for both point and range loci)
@@ -133,11 +133,12 @@ export class NgxSequenceViewerComponent implements OnChanges {
@Input()
public sequence?: string;
- public sequences!: string[];
+ @Input()
+ public sequences?: string[];
public get first(): string {
// Just return first sequence
- return this.sequences[0];
+ return (this.sequences as string[])[0];
}
public get length(): number {
@@ -178,7 +179,7 @@ export class NgxSequenceViewerComponent implements OnChanges {
const styles: Record> = {};
// Define sequences: index, consensus, input sequences
const consensus = this.consensus.map(([aa]) => aa).join('');
- const sequences = [consensus, ...this.sequences];
+ const sequences = [consensus, ...this.sequences || []];
// Loop through each row (sequence)
for (let i = 0; i < sequences.length; i++) {
// Update index
@@ -328,10 +329,18 @@ export class NgxSequenceViewerComponent implements OnChanges {
* If expectations are not met, then an error is thrown.
*/
public setSequences(): void {
+ // Case sequences are provided
+ if (this.sequences && this.labels) {
+ // Check whether the size of sequences and labels match
+ if (this.sequences.length !== this.labels.length) {
+ // Otherwise, throw an error
+ throw new Error('Number of sequences does not match number of labels');
+ }
+ }
// Case fasta file is provided
- if (this.fasta) {
+ else if (this.fasta) {
// Attempt to parse fasta file
- const parsed = parseFasta(this.fasta);
+ const parsed = FASTA.parse(this.fasta);
// Set sequences and labels
this.sequences = parsed.map((entry) => entry.sequence);
this.labels = this.labels || parsed.map((entry) => entry.label);
@@ -401,14 +410,16 @@ export class NgxSequenceViewerComponent implements OnChanges {
public setLogo(): void {
// Initialize logo
this.logo = [];
+ // define sequences
+ const sequences = this.sequences || [];
// Define number of sequences
- const count = this.sequences.length;
+ const count = sequences.length;
// Loop through each position in the alignment
for (let i = 0; i < this.length; i++) {
// Define a position in the logo
let position: { [aa: string]: number } = {};
// Loop through each sequence in the alignment
- for (const sequence of this.sequences) {
+ for (const sequence of sequences) {
// Get amino acid in current position
const aa = sequence[i];
// Update count of amino acid in position
diff --git a/projects/utils/mmcif.spec.ts b/projects/ngx-sequence-viewer/src/lib/utils.spec.ts
similarity index 100%
rename from projects/utils/mmcif.spec.ts
rename to projects/ngx-sequence-viewer/src/lib/utils.spec.ts
diff --git a/projects/ngx-sequence-viewer/src/lib/utils.ts b/projects/ngx-sequence-viewer/src/lib/utils.ts
index 659192a..bcee1a4 100644
--- a/projects/ngx-sequence-viewer/src/lib/utils.ts
+++ b/projects/ngx-sequence-viewer/src/lib/utils.ts
@@ -1,9 +1,39 @@
-/** Parse fasta file
-*
-* @param {string} text - Input text, in fasta format.
-* @returns {{ sequence: string, label: string }[]} - Parsed sequences and labels.
-*/
-export function parseFasta(text: string): { sequence: string, label: string }[] {
+export abstract class Parser {
+
+ protected abstract parseText(text: string): T;
+
+ protected parseFile(file: Blob): Promise {
+ // Cast input file to string
+ const reader = new FileReader();
+ // Read file as text
+ reader.readAsText(file, 'utf-8');
+ // Return promise
+ return new Promise((resolve, reject) => {
+ // Resolve promise with parsed text
+ reader.onload = () => resolve(this.parseText('' + reader.result));
+ // Reject promise with error
+ reader.onerror = error => reject(error);
+ });
+
+ }
+
+ public parse(input: string): T;
+ public parse(input: Blob): Promise;
+ public parse(input: Blob | string): T | Promise {
+ // Case input is not a string
+ if (typeof input !== 'string') {
+ // Then parse file
+ return this.parseFile(input);
+ }
+ // Otherwise, just parse text
+ return this.parseText('' + input);
+ }
+}
+
+export type Sequence = { sequence: string, label: string };
+
+class FastaParser extends Parser {
+ protected override parseText(text: string): Sequence[] {
// Split line by newline character
const lines = text.split(/[\n\r]+/);
// Define output
@@ -28,4 +58,8 @@ export function parseFasta(text: string): { sequence: string, label: string }[]
}
// Return parsed sequences and labels
return parsed;
- }
\ No newline at end of file
+ }
+}
+
+// Export single instance of fasta parser
+export const FASTA = new FastaParser();
diff --git a/projects/ngx-sequence-viewer/tsconfig.lib.prod.json b/projects/ngx-sequence-viewer/tsconfig.lib.prod.json
index 06de549..a2ca365 100644
--- a/projects/ngx-sequence-viewer/tsconfig.lib.prod.json
+++ b/projects/ngx-sequence-viewer/tsconfig.lib.prod.json
@@ -2,7 +2,8 @@
{
"extends": "./tsconfig.lib.json",
"compilerOptions": {
- "declarationMap": false
+ "declarationMap": false,
+
},
"angularCompilerOptions": {
"compilationMode": "partial"
diff --git a/projects/utils/fasta.ts b/projects/utils/fasta.ts
deleted file mode 100644
index 3a60c70..0000000
--- a/projects/utils/fasta.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { Parser } from './parser';
-
-export type Sequence = { sequence: string, label: string };
-
-class FastaParser extends Parser {
-
- public override parseText(text: string): Sequence[] {
- // Split line by newline character
- const lines = text.split(/[\n\r]+/);
- // Define output
- const parsed: { sequence: string, label: string }[] = [];
- // Define current index
- let index = -1;
- // Loop through each line
- for (let line of lines) {
- // Sanitize line
- line = line.trim();
- // In case line starts with '>' character, then define new sequence entry
- if (line.startsWith('>')) {
- // Define new sequence entry
- parsed.push({ sequence: '', label: line.slice(1) });
- // Update index
- index++
- }
- // In case index (0) has been defined beforehand, then current line is sequence
- else if (index > -1) parsed[index].sequence += line;
- // Otherwise, fine is not fasta formatted and an error is thrown
- else throw new Error('Provided text is not in fasta format');
- }
- // Return parsed sequences and labels
- return parsed;
- }
-
-}
-
-export const FASTA = new FastaParser();
\ No newline at end of file
diff --git a/projects/utils/index.ts b/projects/utils/index.ts
deleted file mode 100644
index b79a817..0000000
--- a/projects/utils/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export { MMCIF, Residues, Residue } from './mmcif';
-export { FASTA, Sequence } from './fasta';
diff --git a/projects/utils/mmcif.ts b/projects/utils/mmcif.ts
deleted file mode 100644
index 1d497e2..0000000
--- a/projects/utils/mmcif.ts
+++ /dev/null
@@ -1,123 +0,0 @@
-import { Parser } from './parser';
-
-export interface Residue {
- // Define sequence number
- authSeqId: number;
- // Define residue's insertion code
- pdbInsCode: string;
- // Define residue's name (one letter code)
- authCompId: string;
-}
-
-export type Residues = {
- [model: number]: {
- [chain: string]: Residue[]
- }
-}
-
-class MMCIFParser extends Parser {
-
- readonly ThreeToOne = {
- 'ALA': 'A', 'ARG': 'R', 'ASN': 'N', 'ASP': 'D', 'CYS': 'C',
- 'GLN': 'Q', 'GLU': 'E', 'GLY': 'G', 'HIS': 'H', 'ILE': 'I',
- 'LEU': 'L', 'LYS': 'K', 'MET': 'M', 'PHE': 'F', 'PRO': 'P',
- 'SER': 'S', 'THR': 'T', 'TRP': 'W', 'TYR': 'Y', 'VAL': 'V'
- }
-
- readonly OneToThree = {
- 'A': 'ALA', 'R': 'ARG', 'N': 'ASN', 'D': 'ASP', 'C': 'CYS',
- 'Q': 'GLN', 'E': 'GLU', 'G': 'GLY', 'H': 'HIS', 'I': 'ILE',
- 'L': 'LEU', 'K': 'LYS', 'M': 'MET', 'F': 'PHE', 'P': 'PRO',
- 'S': 'SER', 'T': 'THR', 'W': 'TRP', 'Y': 'TYR', 'V': 'VAL'
- };
-
- public override parseText(text: string): Residues {
- // Split text in lines
- const lines = text.split('\n');
- // Initialize table, each item is a column
- const table: Record = {};
- // Initialize column to index mapping
- const columns: Record = {};
- // Loop through each line
- for (let i = 0; i < lines.length; i++) {
- // Sanitize line
- let line = lines[i] = (lines[i]).trim();
- // Check for lines starting with _atom
- if (line.startsWith('_atom_site.')) {
- // Initialize index for culumns
- let j = 0;
- // Loop through each following line
- for (j; i + j < lines.length; j++) {
- // Sanitize line
- line = lines[i + j] = (lines[i + j]).trim();
- // Loop through each column in table
- if (line.startsWith('_atom_site.')) {
- // Initialize column key
- const column = columns[j] = line;
- // Initialize column values
- table[column] = [];
- }
- // Otherwise, break loop
- else break;
- }
- // Update index
- i = i + j;
- }
- // Otherwise, check if columns are defined
- else if (table['_atom_site.id']) {
- // Loop through each row
- for (let j = 0; i + j < lines.length; j++) {
- // Define current line
- line = lines[i + j] = (lines[i + j]).trim();
- // Case line does not contain stop character
- if (line !== '#') {
- // Split line in columns
- const values = line.split(/\s+/);
- // Loop through each value
- for (const [index, value] of values.entries()) {
- // Get column key
- const column = columns[index];
- // Add value to column
- table[column].push(value.replace(/\?/g, ''));
- }
- }
- // Otherwise, break all loops
- else i = j = lines.length;
- }
- }
- }
- // Initialize residues
- const residues: Residues = {};
- // Define length of table (as number of items in first column)
- const length = table['_atom_site.id'].length;
- // Group each item in table by `author_asym_id`
- for (let i = 0; i < length; i++) {
- // Get chain identifier
- const authAsymId = '' + table['_atom_site.auth_asym_id'][i];
- // Get model number
- const pdbxPDBModelNum = parseInt('' + table['_atom_site.pdbx_PDB_model_num'][i]);
- // Get residue name
- const authCompId = '' + table['_atom_site.label_comp_id'][i];
- // Get residue number
- const authSeqId = parseInt('' + table['_atom_site.auth_seq_id'][i]);
- // Get residue insertion code
- const pdbxPDBInsCode = '' + table['_atom_site.pdbx_PDB_ins_code'][i];
- // Initialize model
- residues[pdbxPDBModelNum] = residues[pdbxPDBModelNum] || {};
- // Initialize chain
- const residueList = residues[pdbxPDBModelNum][authAsymId] = residues[pdbxPDBModelNum][authAsymId] || [];
- // Initialize residue
- const currentResidue = { authSeqId, pdbInsCode: pdbxPDBInsCode, authCompId: authCompId };
- const previousResidue = residueList.length > 0 ? residueList[residueList.length - 1] : undefined;
- // Define previous residue
- if (!previousResidue || previousResidue.authSeqId !== authSeqId || previousResidue.pdbInsCode !== pdbxPDBInsCode) {
- // Add residue to chain
- residueList.push(currentResidue);
- }
- }
- // Return residues
- return residues;
- }
-}
-
-export const MMCIF = new MMCIFParser();
\ No newline at end of file
diff --git a/projects/utils/parser.spec.ts b/projects/utils/parser.spec.ts
deleted file mode 100644
index e69de29..0000000
diff --git a/projects/utils/parser.ts b/projects/utils/parser.ts
deleted file mode 100644
index 76e78e4..0000000
--- a/projects/utils/parser.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-export abstract class Parser {
-
- protected abstract parseText(text: string): T;
-
- protected parseFile(file: Blob): Promise {
- // Cast input file to string
- const reader = new FileReader();
- // Read file as text
- reader.readAsText(file, 'utf-8');
- // Return promise
- return new Promise((resolve, reject) => {
- // Resolve promise with parsed text
- reader.onload = () => resolve(this.parseText('' + reader.result));
- // Reject promise with error
- reader.onerror = error => reject(error);
- });
-
- }
-
- public parse(input: string): T;
- public parse(input: Blob): Promise;
- public parse(input: Blob | string): T | Promise {
- // Case input is not a string
- if (typeof input !== 'string') {
- // Then parse file
- return this.parseFile(input);
- }
- // Otherwise, just parse text
- return this.parseText('' + input);
- }
-}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index d0466db..b668a82 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -20,15 +20,9 @@
"@ngx-sequence-viewer": [
"./projects/ngx-sequence-viewer/src/public-api"
],
- // "ngx-sequence-viewer": [
- // "./dist/ngx-sequence-viewer"
- // ],
- // "ngx-features-viewer": [
- // "./dist/ngx-features-viewer",
- // ],
- // "ngx-structure-viewer": [
- // "./dist/ngx-structure-viewer"
- // ]
+ "@utils": [
+ "./projects/utils/index"
+ ]
},
"sourceMap": true,
"declaration": false,