-
Sebastian Bittrich authoredSebastian Bittrich authored
render-structure.ts 5.19 KiB
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import './index.html'
import { Canvas3D } from 'mol-canvas3d/canvas3d';
import CIF, { CifFrame } from 'mol-io/reader/cif'
import { Model, Structure, StructureElement, Unit } from 'mol-model/structure';
import { ColorTheme, LocationColor } from 'mol-theme/color';
import { SizeTheme } from 'mol-theme/size';
import { CartoonRepresentationProvider } from 'mol-repr/structure/representation/cartoon';
import { trajectoryFromMmCIF } from 'mol-model-formats/structure/mmcif';
import { AccessibleSurfaceArea } from 'mol-model/structure/structure/accessible-surface-area';
import { Color, ColorScale } from 'mol-util/color';
import { Location } from 'mol-model/location';
import { ThemeDataContext } from 'mol-theme/theme';
import { ParamDefinition as PD } from 'mol-util/param-definition';
import { ColorListName, ColorListOptions } from 'mol-util/color/scale';
const parent = document.getElementById('app')!
parent.style.width = '100%'
parent.style.height = '100%'
const canvas = document.createElement('canvas')
canvas.style.width = '100%'
canvas.style.height = '100%'
parent.appendChild(canvas)
const canvas3d = Canvas3D.create(canvas, parent)
canvas3d.animate()
async function parseCif(data: string|Uint8Array) {
const comp = CIF.parse(data);
const parsed = await comp.run();
if (parsed.isError) throw parsed;
return parsed.result;
}
async function downloadCif(url: string, isBinary: boolean) {
const data = await fetch(url);
return parseCif(isBinary ? new Uint8Array(await data.arrayBuffer()) : await data.text());
}
async function downloadFromPdb(pdb: string) {
// const parsed = await downloadCif(`https://files.rcsb.org/download/${pdb}.cif`, false);
const parsed = await downloadCif(`https://webchem.ncbr.muni.cz/ModelServer/static/bcif/${pdb}`, true);
return parsed.blocks[0];
}
async function getModels(frame: CifFrame) {
return await trajectoryFromMmCIF(frame).run();
}
async function getStructure(model: Model) {
return Structure.ofModel(model);
}
const reprCtx = {
colorThemeRegistry: ColorTheme.createRegistry(),
sizeThemeRegistry: SizeTheme.createRegistry()
}
function getCartoonRepr() {
return CartoonRepresentationProvider.factory(reprCtx, CartoonRepresentationProvider.getParams)
}
let accessibleSurfaceArea: AccessibleSurfaceArea;
async function init(props = {}) {
const cif = await downloadFromPdb(
// '3j3q'
'1aon'
// '1acj'
// '1pga'
)
const models = await getModels(cif)
const structure = await getStructure(models[0])
// async compute ASA
accessibleSurfaceArea = await AccessibleSurfaceArea.compute(structure)
const cartoonRepr = getCartoonRepr()
// create color theme
cartoonRepr.setTheme({
color: AccessibleSurfaceAreaColorTheme(reprCtx, { ...PD.getDefaultValues(AccessibleSurfaceAreaColorThemeParams), ...props }),
size: reprCtx.sizeThemeRegistry.create('uniform', { structure })
})
await cartoonRepr.createOrUpdate({ ...CartoonRepresentationProvider.defaultValues, quality: 'auto' }, structure).run()
canvas3d.add(cartoonRepr)
canvas3d.resetCamera()
}
init()
const DefaultColor = Color(0xFFFFFF)
const Description = 'Assigns a color based on the relative accessible surface area of a residue.'
export const AccessibleSurfaceAreaColorThemeParams = {
list: PD.ColorScale<ColorListName>('Rainbow', ColorListOptions)
}
export type AccessibleSurfaceAreaColorThemeParams = typeof AccessibleSurfaceAreaColorThemeParams
export function getAccessibleSurfaceAreaColorThemeParams(ctx: ThemeDataContext) {
return AccessibleSurfaceAreaColorThemeParams // TODO return copy
}
export function AccessibleSurfaceAreaColorTheme(ctx: ThemeDataContext, props: PD.Values<AccessibleSurfaceAreaColorThemeParams>): ColorTheme<AccessibleSurfaceAreaColorThemeParams> {
let color: LocationColor = () => DefaultColor
const scale = ColorScale.create({
listOrName: props.list,
minLabel: '0.0 (buried)',
maxLabel: '1.0 (exposed)',
domain: [0.0, 1.0]
})
color = (location: Location): Color => {
if (StructureElement.isLocation(location)) {
if (Unit.isAtomic(location.unit)) {
const value = accessibleSurfaceArea.relativeAccessibleSurfaceArea![location.unit.residueIndex[location.element]];
return value !== AccessibleSurfaceArea.VdWLookup[0] /* signals missing value */ ? scale.color(value) : DefaultColor;
}
}
return DefaultColor
}
return {
factory: AccessibleSurfaceAreaColorTheme,
granularity: 'group',
color,
props,
description: Description,
legend: scale ? scale.legend : undefined
}
}
export const AccessibleSurfaceAreaColorThemeProvider: ColorTheme.Provider<AccessibleSurfaceAreaColorThemeParams> = {
label: 'Accessible Surface Area',
factory: AccessibleSurfaceAreaColorTheme,
getParams: getAccessibleSurfaceAreaColorThemeParams,
defaultValues: PD.getDefaultValues(AccessibleSurfaceAreaColorThemeParams),
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
}