Skip to content
Snippets Groups Projects
Commit 289dc09e authored by dsehnal's avatar dsehnal
Browse files

add support for atom_site.pdbx_sifts_xref export

parent f23f84f0
Branches
No related tags found
No related merge requests found
......@@ -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
......
......@@ -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
......
......@@ -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 };
......
......@@ -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);
}
}
}
......
......@@ -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()
}))
......
......@@ -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;
......
......@@ -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>
</>;
}
......
......@@ -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';
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment