Jelajahi Sumber

add support for atom_site.pdbx_sifts_xref export

dsehnal 3 tahun lalu
induk
melakukan
289dc09eae

+ 4 - 0
data/cif-field-names/mmcif-field-names.csv

@@ -24,6 +24,10 @@ atom_site.auth_asym_id
 atom_site.auth_seq_id
 atom_site.pdbx_PDB_model_num
 atom_site.ihm_model_id
+atom_site.pdbx_sifts_xref_db_name
+atom_site.pdbx_sifts_xref_db_acc
+atom_site.pdbx_sifts_xref_db_num
+atom_site.pdbx_sifts_xref_db_res
 
 atom_site_anisotrop.id
 atom_site_anisotrop.U

+ 17 - 0
src/mol-io/reader/cif/schema/mmcif.ts

@@ -215,6 +215,23 @@ export const mmCIF_Schema = {
          * formal charge assignment normally found in chemical diagrams.
          */
         pdbx_formal_charge: int,
+        /**
+         * The name of additional external databases with residue level mapping.
+         */
+        pdbx_sifts_xref_db_name: str,
+        /**
+         * The accession code related to the additional external database entry.
+         */
+        pdbx_sifts_xref_db_acc: str,
+        /**
+         * The sequence position of the external database entry that corresponds
+         * to the residue mapping defined by the SIFTS process.
+         */
+        pdbx_sifts_xref_db_num: str,
+        /**
+         * Describes the residue type of the given UniProt match
+         */
+        pdbx_sifts_xref_db_res: str,
         /**
          * The model id corresponding to the atom site.
          * This data item is a pointer to _ihm_model_list.model_id

+ 35 - 21
src/mol-model-props/sequence/best-database-mapping.ts → src/mol-model-props/sequence/sifts-mapping.ts

@@ -11,30 +11,43 @@ import { Model } from '../../mol-model/structure';
 import { StructureElement } from '../../mol-model/structure/structure';
 import { CustomModelProperty } from '../common/custom-model-property';
 
-export { BestDatabaseSequenceMapping };
+export { SIFTSMapping as SIFTSMapping };
 
-interface BestDatabaseSequenceMapping {
+interface SIFTSMappingMapping {
     readonly dbName: string[],
     readonly accession: string[],
-    readonly num: number[],
+    readonly num: string[],
     readonly residue: string[]
 }
 
-namespace BestDatabaseSequenceMapping {
-    export const Provider: CustomModelProperty.Provider<{}, BestDatabaseSequenceMapping> = CustomModelProperty.createProvider({
-        label: 'Best Database Sequence Mapping',
+namespace SIFTSMapping {
+    export const Provider: CustomModelProperty.Provider<{}, SIFTSMappingMapping> = CustomModelProperty.createProvider({
+        label: 'SIFTS Mapping',
         descriptor: CustomPropertyDescriptor({
-            name: 'molstar_best_database_sequence_mapping'
+            name: 'sifts_sequence_mapping'
         }),
         type: 'static',
         defaultParams: {},
         getParams: () => ({}),
-        isApplicable: (data: Model) => MmcifFormat.is(data.sourceData) && data.sourceData.data.frame.categories?.atom_site?.fieldNames.indexOf('pdbx_sifts_xref_db_name') >= 0,
+        isApplicable: (data: Model) => isAvailable(data),
         obtain: async (ctx, data) => {
             return { value: fromCif(data) };
         }
     });
 
+    export function isAvailable(model: Model) {
+        if (!MmcifFormat.is(model.sourceData)) return false;
+
+        const {
+            pdbx_sifts_xref_db_name: db_name,
+            pdbx_sifts_xref_db_acc: db_acc,
+            pdbx_sifts_xref_db_num: db_num,
+            pdbx_sifts_xref_db_res: db_res
+        } = model.sourceData.data.db.atom_site;
+
+        return db_name.isDefined && db_acc.isDefined && db_num.isDefined && db_res.isDefined;
+    }
+
     export function getKey(loc: StructureElement.Location) {
         const model = loc.unit.model;
         const data = Provider.get(model).value;
@@ -55,22 +68,23 @@ namespace BestDatabaseSequenceMapping {
         return `${dbName} ${data.accession[rI]} ${data.num[rI]} ${data.residue[rI]}`;
     }
 
-    function fromCif(model: Model): BestDatabaseSequenceMapping | undefined {
+    function fromCif(model: Model): SIFTSMappingMapping | undefined {
         if (!MmcifFormat.is(model.sourceData)) return;
 
-        const { atom_site } = model.sourceData.data.frame.categories;
-        const db_name = atom_site.getField('pdbx_sifts_xref_db_name');
-        const db_acc = atom_site.getField('pdbx_sifts_xref_db_acc');
-        const db_num = atom_site.getField('pdbx_sifts_xref_db_num');
-        const db_res = atom_site.getField('pdbx_sifts_xref_db_res');
+        const {
+            pdbx_sifts_xref_db_name: db_name,
+            pdbx_sifts_xref_db_acc: db_acc,
+            pdbx_sifts_xref_db_num: db_num,
+            pdbx_sifts_xref_db_res: db_res
+        } = model.sourceData.data.db.atom_site;
 
-        if (!db_name || !db_acc || !db_num || !db_res) return;
+        if (!db_name.isDefined || !db_acc.isDefined || !db_num.isDefined || !db_res.isDefined) return;
 
         const { atomSourceIndex } = model.atomicHierarchy;
         const { count, offsets: residueOffsets } = model.atomicHierarchy.residueAtomSegments;
         const dbName = new Array<string>(count);
         const accession = new Array<string>(count);
-        const num = new Array<number>(count);
+        const num = new Array<string>(count);
         const residue = new Array<string>(count);
 
         for (let i = 0; i < count; i++) {
@@ -79,15 +93,15 @@ namespace BestDatabaseSequenceMapping {
             if (db_name.valueKind(row) !== Column.ValueKind.Present) {
                 dbName[i] = '';
                 accession[i] = '';
-                num[i] = 0;
+                num[i] = '';
                 residue[i] = '';
                 continue;
             }
 
-            dbName[i] = db_name.str(row);
-            accession[i] = db_acc.str(row);
-            num[i] = db_num.int(row);
-            residue[i] = db_res.str(row);
+            dbName[i] = db_name.value(row);
+            accession[i] = db_acc.value(row);
+            num[i] = db_num.value(row);
+            residue[i] = db_res.value(row);
         }
 
         return { dbName, accession, num, residue };

+ 6 - 6
src/mol-model-props/sequence/themes/best-database-mapping.ts

@@ -12,7 +12,7 @@ import { Color } from '../../../mol-util/color';
 import { getPalette, getPaletteParams } from '../../../mol-util/color/palette';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { CustomProperty } from '../../common/custom-property';
-import { BestDatabaseSequenceMapping } from '../best-database-mapping';
+import { SIFTSMapping } from '../sifts-mapping';
 
 const DefaultColor = Color(0xFAFAFA);
 const Description = 'Assigns a color based on best dababase sequence mapping.';
@@ -32,7 +32,7 @@ export function BestDatabaseSequenceMappingColorTheme(ctx: ThemeDataContext, pro
 
     if (ctx.structure) {
         for (const m of ctx.structure.models) {
-            const mapping = BestDatabaseSequenceMapping.Provider.get(m).value;
+            const mapping = SIFTSMapping.Provider.get(m).value;
             if (!mapping) continue;
             for (const acc of mapping.accession) {
                 if (!acc || globalAccessionMap.has(acc)) continue;
@@ -45,7 +45,7 @@ export function BestDatabaseSequenceMappingColorTheme(ctx: ThemeDataContext, pro
         const colorMap = new Map<string, Color>();
 
         const getColor = (location: StructureElement.Location) => {
-            const key = BestDatabaseSequenceMapping.getKey(location);
+            const key = SIFTSMapping.getKey(location);
             if (!key) return DefaultColor;
 
             if (colorMap.has(key)) return colorMap.get(key)!;
@@ -86,19 +86,19 @@ export const BestDatabaseSequenceMappingColorThemeProvider: ColorTheme.Provider<
     factory: BestDatabaseSequenceMappingColorTheme,
     getParams: getBestDatabaseSequenceMappingColorThemeParams,
     defaultValues: PD.getDefaultValues(BestDatabaseSequenceMappingColorThemeParams),
-    isApplicable: (ctx: ThemeDataContext) => !!ctx.structure?.models.some(m => BestDatabaseSequenceMapping.Provider.isApplicable(m)),
+    isApplicable: (ctx: ThemeDataContext) => !!ctx.structure?.models.some(m => SIFTSMapping.Provider.isApplicable(m)),
     ensureCustomProperties: {
         attach: async (ctx: CustomProperty.Context, data: ThemeDataContext) => {
             if (!data.structure) return;
 
             for (const m of data.structure.models) {
-                await BestDatabaseSequenceMapping.Provider.attach(ctx, m, void 0, true);
+                await SIFTSMapping.Provider.attach(ctx, m, void 0, true);
             }
         },
         detach: (data) => {
             if (!data.structure) return;
             for (const m of data.structure.models) {
-                BestDatabaseSequenceMapping.Provider.ref(m, false);
+                SIFTSMapping.Provider.ref(m, false);
             }
         }
     }

+ 69 - 2
src/mol-model/structure/export/categories/atom_site.ts

@@ -5,7 +5,11 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
+import { Column } from '../../../../mol-data/db';
+import { mmCIF_Database } from '../../../../mol-io/reader/cif/schema/mmcif';
 import { CifWriter } from '../../../../mol-io/writer/cif';
+import { MmcifFormat } from '../../../../mol-model-formats/structure/mmcif';
+import { SIFTSMapping } from '../../../../mol-model-props/sequence/sifts-mapping';
 import { StructureElement, Structure, StructureProperties as P } from '../../structure';
 import { CifExportContext } from '../mmcif';
 import CifField = CifWriter.Field
@@ -26,7 +30,53 @@ function atom_site_auth_asym_id(e: StructureElement.Location) {
     return l + suffix;
 }
 
-const atom_site_fields = () => CifWriter.fields<StructureElement.Location, Structure>()
+const SIFTS = {
+    shouldInclude(s: AtomSiteData) {
+        return SIFTSMapping.isAvailable(s.structure.models[0]);
+    },
+    pdbx_sifts_xref_db_name: {
+        value(e: StructureElement.Location, d: AtomSiteData) {
+            const srcIndex = d.sourceIndex.value(e.element);
+            return d.atom_site!.pdbx_sifts_xref_db_name.value(srcIndex);
+        },
+        valueKind(e: StructureElement.Location, d: any) {
+            const srcIndex = d.sourceIndex.value(e.element);
+            return d.atom_site!.pdbx_sifts_xref_db_name.valueKind(srcIndex);
+        },
+    },
+    pdbx_sifts_xref_db_acc: {
+        value(e: StructureElement.Location, d: AtomSiteData) {
+            const srcIndex = d.sourceIndex.value(e.element);
+            return d.atom_site!.pdbx_sifts_xref_db_acc.value(srcIndex);
+        },
+        valueKind(e: StructureElement.Location, d: any) {
+            const srcIndex = d.sourceIndex.value(e.element);
+            return d.atom_site!.pdbx_sifts_xref_db_acc.valueKind(srcIndex);
+        },
+    },
+    pdbx_sifts_xref_db_num: {
+        value(e: StructureElement.Location, d: AtomSiteData) {
+            const srcIndex = d.sourceIndex.value(e.element);
+            return d.atom_site!.pdbx_sifts_xref_db_num.value(srcIndex);
+        },
+        valueKind(e: StructureElement.Location, d: any) {
+            const srcIndex = d.sourceIndex.value(e.element);
+            return d.atom_site!.pdbx_sifts_xref_db_num.valueKind(srcIndex);
+        },
+    },
+    pdbx_sifts_xref_db_res: {
+        value(e: StructureElement.Location, d: AtomSiteData) {
+            const srcIndex = d.sourceIndex.value(e.element);
+            return d.atom_site!.pdbx_sifts_xref_db_res.value(srcIndex);
+        },
+        valueKind(e: StructureElement.Location, d: any) {
+            const srcIndex = d.sourceIndex.value(e.element);
+            return d.atom_site!.pdbx_sifts_xref_db_res.valueKind(srcIndex);
+        },
+    }
+};
+
+const atom_site_fields = () => CifWriter.fields<StructureElement.Location, AtomSiteData>()
     .str('group_PDB', P.residue.group_PDB)
     .index('id')
     .str('type_symbol', P.atom.type_symbol as any)
@@ -62,18 +112,35 @@ const atom_site_fields = () => CifWriter.fields<StructureElement.Location, Struc
     .str('auth_asym_id', atom_site_auth_asym_id)
 
     .int('pdbx_PDB_model_num', P.unit.model_num, { encoder: E.deltaRLE })
+
+    // SIFTS
+    .str('pdbx_sifts_xref_db_name', SIFTS.pdbx_sifts_xref_db_name.value, { shouldInclude: SIFTS.shouldInclude, valueKind: SIFTS.pdbx_sifts_xref_db_name.valueKind })
+    .str('pdbx_sifts_xref_db_acc', SIFTS.pdbx_sifts_xref_db_acc.value, { shouldInclude: SIFTS.shouldInclude, valueKind: SIFTS.pdbx_sifts_xref_db_acc.valueKind })
+    .str('pdbx_sifts_xref_db_num', SIFTS.pdbx_sifts_xref_db_num.value, { shouldInclude: SIFTS.shouldInclude, valueKind: SIFTS.pdbx_sifts_xref_db_num.valueKind })
+    .str('pdbx_sifts_xref_db_res', SIFTS.pdbx_sifts_xref_db_res.value, { shouldInclude: SIFTS.shouldInclude, valueKind: SIFTS.pdbx_sifts_xref_db_res.valueKind })
+
     // .str('operator_name', P.unit.operator_name, {
     //     shouldInclude: structure => structure.units.some(u => !u.conformation.operator.isIdentity)
     // })
     .getFields();
 
+interface AtomSiteData {
+    structure: Structure,
+    sourceIndex: Column<number>,
+    atom_site?: mmCIF_Database['atom_site']
+}
+
 export const _atom_site: CifCategory<CifExportContext> = {
     name: 'atom_site',
     instance({ structures }: CifExportContext) {
         return {
             fields: atom_site_fields(),
             source: structures.map(s => ({
-                data: s,
+                data: {
+                    structure: s,
+                    sourceIndex: s.model.atomicHierarchy.atomSourceIndex,
+                    atom_site: MmcifFormat.is(s.model.sourceData) ? s.model.sourceData.data.db.atom_site : void 0
+                } as AtomSiteData,
                 rowCount: s.elementCount,
                 keys: () => s.elementLocations()
             }))

+ 2 - 3
src/mol-model/structure/structure/util/superposition-db-mapping.ts

@@ -7,7 +7,7 @@
 import { Segmentation } from '../../../../mol-data/int';
 import { Mat4 } from '../../../../mol-math/linear-algebra';
 import { MinimizeRmsd } from '../../../../mol-math/linear-algebra/3d/minimize-rmsd';
-import { BestDatabaseSequenceMapping } from '../../../../mol-model-props/sequence/best-database-mapping';
+import { SIFTSMapping } from '../../../../mol-model-props/sequence/sifts-mapping';
 import { ElementIndex } from '../../model/indexing';
 import { Structure } from '../structure';
 import { Unit } from '../unit';
@@ -34,7 +34,6 @@ export function alignAndSuperposeWithBestDatabaseMapping(structures: Structure[]
     for (const p of pairs) {
         const [a, b] = getPositionTables(index, p.i, p.j, p.count);
         const transform = MinimizeRmsd.compute({ a, b });
-        console.log(Mat4.makeTable(transform.bTransform), transform.rmsd);
         ret.push({ transform, pivot: p.i, other: p.j });
     }
 
@@ -127,7 +126,7 @@ function buildIndex(structure: Structure, index: Map<string, IndexEntry>, sI: nu
 
         const { elements, model } = unit;
 
-        const map = BestDatabaseSequenceMapping.Provider.get(model).value;
+        const map = SIFTSMapping.Provider.get(model).value;
         if (!map) return;
 
         const { dbName, accession, num } = map;

+ 4 - 4
src/mol-plugin-ui/structure/superposition.tsx

@@ -22,7 +22,7 @@ import { StructureSelectionHistoryEntry } from '../../mol-plugin-state/manager/s
 import { ToggleSelectionModeButton } from './selection';
 import { alignAndSuperposeWithBestDatabaseMapping } from '../../mol-model/structure/structure/util/superposition-db-mapping';
 import { PluginCommands } from '../../mol-plugin/commands';
-import { BestDatabaseSequenceMapping } from '../../mol-model-props/sequence/best-database-mapping';
+import { SIFTSMapping } from '../../mol-model-props/sequence/sifts-mapping';
 
 export class StructureSuperpositionControls extends CollapsableControls {
     defaultState() {
@@ -94,7 +94,7 @@ export class SuperpositionControls extends PurePluginUIComponent<{ }, Superposit
         });
 
         this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, sel => {
-            this.setState({ canUseDb: sel.structures.every(s => !!s.cell.obj?.data && s.cell.obj.data.models.some(m => BestDatabaseSequenceMapping.Provider.isApplicable(m))) });
+            this.setState({ canUseDb: sel.structures.every(s => !!s.cell.obj?.data && s.cell.obj.data.models.some(m => SIFTSMapping.Provider.isApplicable(m))) });
         });
     }
 
@@ -323,8 +323,8 @@ export class SuperpositionControls extends PurePluginUIComponent<{ }, Superposit
 
     superposeByDbMapping() {
         return <>
-            <Button icon={SuperposeChainsSvg} title='Superpose structures using database mapping.' className='msp-btn msp-btn-block' onClick={this.superposeDb} style={{ marginTop: '1px' }} disabled={this.state.isBusy}>
-                DB
+            <Button icon={SuperposeChainsSvg} title='Superpose structures using UNIPROT mapping.' className='msp-btn msp-btn-block' onClick={this.superposeDb} style={{ marginTop: '1px' }} disabled={this.state.isBusy}>
+                Uniprot
             </Button>
         </>;
     }

+ 1 - 1
src/mol-plugin/behavior/dynamic/custom-props/sequence/best-database-mapping.ts

@@ -5,7 +5,7 @@
  */
 
 import { OrderedSet } from '../../../../../mol-data/int';
-import { BestDatabaseSequenceMapping as BestDatabaseSequenceMappingProp } from '../../../../../mol-model-props/sequence/best-database-mapping';
+import { SIFTSMapping as BestDatabaseSequenceMappingProp } from '../../../../../mol-model-props/sequence/sifts-mapping';
 import { BestDatabaseSequenceMappingColorThemeProvider } from '../../../../../mol-model-props/sequence/themes/best-database-mapping';
 import { Loci } from '../../../../../mol-model/loci';
 import { StructureElement } from '../../../../../mol-model/structure';