Skip to content
Snippets Groups Projects
Commit b00e951d authored by David Sehnal's avatar David Sehnal
Browse files

wip, custom props (take prop from CIF if present otherwise call API)

parent b3c31bb2
No related branches found
No related tags found
No related merge requests found
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { mmCIF_Schema } from './mmcif';
export const mmCIF_residueId_schema = {
label_comp_id: mmCIF_Schema.atom_site.label_comp_id,
label_seq_id: mmCIF_Schema.atom_site.label_seq_id,
pdbx_PDB_ins_code: mmCIF_Schema.atom_site.pdbx_PDB_ins_code,
label_asym_id: mmCIF_Schema.atom_site.label_asym_id,
label_entity_id: mmCIF_Schema.atom_site.label_entity_id,
auth_comp_id: mmCIF_Schema.atom_site.auth_atom_id,
auth_seq_id: mmCIF_Schema.atom_site.auth_seq_id,
auth_asym_id: mmCIF_Schema.atom_site.auth_asym_id
}
\ No newline at end of file
...@@ -9,6 +9,9 @@ import { CifWriter } from 'mol-io/writer/cif'; ...@@ -9,6 +9,9 @@ import { CifWriter } from 'mol-io/writer/cif';
import { Model, ModelPropertyDescriptor, ResidueIndex, Structure, StructureElement, Unit } from 'mol-model/structure'; import { Model, ModelPropertyDescriptor, ResidueIndex, Structure, StructureElement, Unit } from 'mol-model/structure';
import { residueIdFields } from 'mol-model/structure/export/categories/atom_site'; import { residueIdFields } from 'mol-model/structure/export/categories/atom_site';
import CifField = CifWriter.Field; import CifField = CifWriter.Field;
import { mmCIF_residueId_schema } from 'mol-io/reader/cif/schema/mmcif-extras';
import { Column, Table } from 'mol-data/db';
import { toTable } from 'mol-io/reader/cif/schema';
type IssueMap = Map<ResidueIndex, string[]> type IssueMap = Map<ResidueIndex, string[]>
...@@ -19,13 +22,18 @@ const _Descriptor: ModelPropertyDescriptor = { ...@@ -19,13 +22,18 @@ const _Descriptor: ModelPropertyDescriptor = {
prefix: 'pdbe', prefix: 'pdbe',
categories: [{ categories: [{
name: 'pdbe_structure_quality_report', name: 'pdbe_structure_quality_report',
instance() {
return { fields: _structure_quality_report_fields, rowCount: 1 }
}
}, {
name: 'pdbe_structure_quality_report_issues',
instance(ctx) { instance(ctx) {
const issues = StructureQualityReport.get(ctx.model); const issues = StructureQualityReport.get(ctx.model);
if (!issues) return CifWriter.Category.Empty; if (!issues) return CifWriter.Category.Empty;
const residues = getResidueLoci(ctx.structure, issues); const residues = getResidueLoci(ctx.structure, issues);
return { return {
fields: _structure_quality_report_fields, fields: _structure_quality_report_issues_fields,
data: <ExportCtx>{ model: ctx.model, residues, residueIndex: ctx.model.atomicHierarchy.residueAtomSegments.index, issues }, data: <ExportCtx>{ model: ctx.model, residues, residueIndex: ctx.model.atomicHierarchy.residueAtomSegments.index, issues },
rowCount: residues.length rowCount: residues.length
}; };
...@@ -36,12 +44,16 @@ const _Descriptor: ModelPropertyDescriptor = { ...@@ -36,12 +44,16 @@ const _Descriptor: ModelPropertyDescriptor = {
type ExportCtx = { model: Model, residueIndex: ArrayLike<ResidueIndex>, residues: StructureElement[], issues: IssueMap }; type ExportCtx = { model: Model, residueIndex: ArrayLike<ResidueIndex>, residues: StructureElement[], issues: IssueMap };
const _structure_quality_report_fields: CifField<ResidueIndex, ExportCtx>[] = [ const _structure_quality_report_issues_fields: CifField<ResidueIndex, ExportCtx>[] = [
CifField.index('id'), CifField.index('id'),
...residueIdFields<ResidueIndex, ExportCtx>((k, d) => d.residues[k]), ...residueIdFields<ResidueIndex, ExportCtx>((k, d) => d.residues[k]),
CifField.str<ResidueIndex, ExportCtx>('issues', (i, d) => d.issues.get(d.residueIndex[d.residues[i].element])!.join(',')) CifField.str<ResidueIndex, ExportCtx>('issues', (i, d) => d.issues.get(d.residueIndex[d.residues[i].element])!.join(','))
]; ];
const _structure_quality_report_fields: CifField<ResidueIndex, ExportCtx>[] = [
CifField.str('updated_datetime_utc', () => `${new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')}`)
];
function getResidueLoci(structure: Structure, issues: IssueMap) { function getResidueLoci(structure: Structure, issues: IssueMap) {
const seenResidues = new Set<ResidueIndex>(); const seenResidues = new Set<ResidueIndex>();
const unitGroups = structure.unitSymmetryGroups; const unitGroups = structure.unitSymmetryGroups;
...@@ -67,7 +79,7 @@ function getResidueLoci(structure: Structure, issues: IssueMap) { ...@@ -67,7 +79,7 @@ function getResidueLoci(structure: Structure, issues: IssueMap) {
return loci; return loci;
} }
function createIssueMap(modelData: Model, data: any): IssueMap | undefined { function createIssueMapFromJson(modelData: Model, data: any): IssueMap | undefined {
const ret = new Map<ResidueIndex, string[]>(); const ret = new Map<ResidueIndex, string[]>();
if (!data.molecules) return; if (!data.molecules) return;
...@@ -91,24 +103,52 @@ function createIssueMap(modelData: Model, data: any): IssueMap | undefined { ...@@ -91,24 +103,52 @@ function createIssueMap(modelData: Model, data: any): IssueMap | undefined {
return ret; return ret;
} }
function createIssueMapFromCif(modelData: Model, data: Table<typeof StructureQualityReport.Schema.pdbe_structure_quality_report_issues>): IssueMap | undefined {
const ret = new Map<ResidueIndex, string[]>();
const { label_entity_id, label_asym_id, auth_seq_id, pdbx_PDB_ins_code, issues, _rowCount } = data;
for (let i = 0; i < _rowCount; i++) {
const idx = modelData.atomicHierarchy.findResidueKey(label_entity_id.value(i), label_asym_id.value(i), '', auth_seq_id.value(i), pdbx_PDB_ins_code.value(i));
ret.set(idx, issues.value(i));
}
return ret;
}
export namespace StructureQualityReport { export namespace StructureQualityReport {
export const Descriptor = _Descriptor; export const Descriptor = _Descriptor;
export const Schema = {
pdbe_structure_quality_report: {
updated_datetime_utc: Column.Schema.str
},
pdbe_structure_quality_report_issues: {
id: Column.Schema.int,
...mmCIF_residueId_schema,
issues: Column.Schema.List(',', x => x)
}
}
export async function attachFromCifOrApi(model: Model, params: { export async function attachFromCifOrApi(model: Model, params: {
// provide JSON from api // provide JSON from api
pdbEapiSourceJson?: (model: Model) => Promise<any> PDBe_apiSourceJson?: (model: Model) => Promise<any>
}) { }) {
// TODO: check if present in mmCIF on Model
if (!params.pdbEapiSourceJson) throw new Error('Data source not defined');
if (model.customProperties.has(Descriptor)) return true; if (model.customProperties.has(Descriptor)) return true;
const id = model.label.toLowerCase(); let issueMap;
const json = await params.pdbEapiSourceJson(model);
const data = json[id]; if (model.sourceData.kind === 'mmCIF' && model.sourceData.frame.categoryNames.includes('pdbe_structure_quality_report')) {
if (!data) return false; const data = toTable(Schema.pdbe_structure_quality_report_issues, model.sourceData.frame.categories.pdbe_structure_quality_report);
const issueMap = createIssueMap(model, data); issueMap = createIssueMapFromCif(model, data);
if (!issueMap || issueMap.size === 0) return false; } else if (!params.PDBe_apiSourceJson) {
throw new Error('Data source not defined');
} else {
const id = model.label.toLowerCase();
const json = await params.PDBe_apiSourceJson(model);
const data = json[id];
if (!data) return false;
issueMap = createIssueMapFromJson(model, data);
}
model.customProperties.add(Descriptor); model.customProperties.add(Descriptor);
model._staticPropertyData.__StructureQualityReport__ = issueMap; model._staticPropertyData.__StructureQualityReport__ = issueMap;
......
...@@ -10,7 +10,7 @@ import { fetchRetry } from '../utils/fetch-retry'; ...@@ -10,7 +10,7 @@ import { fetchRetry } from '../utils/fetch-retry';
export function PDBe_structureQualityReport(model: Model) { export function PDBe_structureQualityReport(model: Model) {
return StructureQualityReport.attachFromCifOrApi(model, { return StructureQualityReport.attachFromCifOrApi(model, {
pdbEapiSourceJson: async model => { PDBe_apiSourceJson: async model => {
const rawData = await fetchRetry(`https://www.ebi.ac.uk/pdbe/api/validation/residuewise_outlier_summary/entry/${model.label.toLowerCase()}`, 1500, 5); const rawData = await fetchRetry(`https://www.ebi.ac.uk/pdbe/api/validation/residuewise_outlier_summary/entry/${model.label.toLowerCase()}`, 1500, 5);
return await rawData.json(); return await rawData.json();
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment