format.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. */
  7. import { Trajectory } from '../../mol-model/structure';
  8. import { TrajectoryFormatCategory, TrajectoryFormatProvider } from '../../mol-plugin-state/formats/trajectory';
  9. import { PluginStateObject as SO, PluginStateTransform } from '../../mol-plugin-state/objects';
  10. import { PluginBehavior } from '../../mol-plugin/behavior';
  11. import { PluginContext } from '../../mol-plugin/context';
  12. import { DefaultQueryRuntimeTable } from '../../mol-script/runtime/query/base';
  13. import { StateAction, StateObjectRef } from '../../mol-state';
  14. import { Task } from '../../mol-task';
  15. import { ParamDefinition } from '../../mol-util/param-definition';
  16. import { G3dHeader, getG3dDataBlock, getG3dHeader } from './data';
  17. import { g3dHaplotypeQuery, G3dLabelProvider, trajectoryFromG3D, G3dSymbols, getG3dInfoData } from './model';
  18. import { StateTransforms } from '../../mol-plugin-state/transforms';
  19. import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params';
  20. import { stringToWords } from '../../mol-util/string';
  21. import { objectForEach } from '../../mol-util/object';
  22. export const G3dProvider: TrajectoryFormatProvider = {
  23. label: 'G3D',
  24. description: 'G3D',
  25. category: TrajectoryFormatCategory,
  26. binaryExtensions: ['g3d'],
  27. parse: async (plugin, data) => {
  28. const trajectory = await plugin.state.data.build()
  29. .to(data)
  30. .apply(G3DHeaderFromFile, {}, { state: { isGhost: true } })
  31. .apply(G3DTrajectory)
  32. .commit();
  33. return { trajectory };
  34. },
  35. visuals: defaultStructure
  36. };
  37. async function defaultStructure(plugin: PluginContext, data: { trajectory: StateObjectRef<SO.Molecule.Trajectory> }) {
  38. const builder = plugin.builders.structure;
  39. const model = await builder.createModel(data.trajectory);
  40. if (!model) return;
  41. const structure = await builder.createStructure(model);
  42. const info = getG3dInfoData(model.data!);
  43. if (!info) return;
  44. const components = plugin.build().to(structure);
  45. const repr = createStructureRepresentationParams(plugin, void 0, {
  46. type: 'cartoon',
  47. color: 'polymer-index',
  48. size: 'uniform',
  49. sizeParams: { value: 0.25 }
  50. });
  51. for (const h of info.haplotypes) {
  52. components
  53. .apply(StateTransforms.Model.StructureSelectionFromExpression, { expression: g3dHaplotypeQuery(h), label: stringToWords(h) })
  54. .apply(StateTransforms.Representation.StructureRepresentation3D, repr);
  55. }
  56. await components.commit();
  57. }
  58. export class G3dHeaderObject extends SO.Create<{
  59. header: G3dHeader,
  60. urlOrData: Uint8Array | string,
  61. cache: { [resolution: number]: Trajectory | undefined }
  62. }>({ name: 'G3D Header', typeClass: 'Data' }) { }
  63. export type G3DHeaderFromFile = typeof G3DHeaderFromFile
  64. export const G3DHeaderFromFile = PluginStateTransform.BuiltIn({
  65. name: 'g3d-header-from-file',
  66. display: { name: 'G3D Header', description: 'Parse G3D Header' },
  67. from: SO.Data.Binary,
  68. to: G3dHeaderObject
  69. })({
  70. apply({ a }, plugin: PluginContext) {
  71. return Task.create('Parse G3D', async () => {
  72. const header = await getG3dHeader(plugin, a.data);
  73. return new G3dHeaderObject({ header, urlOrData: a.data, cache: { } }, { label: header.name, description: header.genome });
  74. });
  75. }
  76. });
  77. export type G3DHeaderFromUrl = typeof G3DHeaderFromUrl
  78. export const G3DHeaderFromUrl = PluginStateTransform.BuiltIn({
  79. name: 'g3d-header-from-url',
  80. display: { name: 'G3D Header', description: 'Parse G3D Header' },
  81. params: { url: ParamDefinition.Text('') },
  82. from: SO.Root,
  83. to: G3dHeaderObject
  84. })({
  85. apply({ params }, plugin: PluginContext) {
  86. return Task.create('Parse G3D', async () => {
  87. const header = await getG3dHeader(plugin, params.url);
  88. return new G3dHeaderObject({ header, urlOrData: params.url, cache: { } }, { label: header.name, description: header.genome });
  89. });
  90. }
  91. });
  92. export type G3DTrajectory = typeof G3DHeaderFromUrl
  93. export const G3DTrajectory = PluginStateTransform.BuiltIn({
  94. name: 'g3d-trajecotry',
  95. display: { name: 'G3D Trajectory', description: 'Create G3D Trajectory' },
  96. params: a => {
  97. if (!a) return { resolution: ParamDefinition.Numeric(200000) };
  98. const rs = a.data.header.resolutions;
  99. return {
  100. resolution: ParamDefinition.Select(rs[rs.length - 1], rs.map(r => [r, '' + r] as const))
  101. };
  102. },
  103. from: G3dHeaderObject,
  104. to: SO.Molecule.Trajectory
  105. })({
  106. apply({ a, params }, plugin: PluginContext) {
  107. return Task.create('G3D Trajectory', async ctx => {
  108. if (a.data.cache[params.resolution]) {
  109. return new SO.Molecule.Trajectory(a.data.cache[params.resolution]!, { label: a.label, description: a.description });
  110. }
  111. const data = await getG3dDataBlock(plugin, a.data.header, a.data.urlOrData, params.resolution);
  112. const traj = await trajectoryFromG3D(data).runInContext(ctx);
  113. a.data.cache[params.resolution] = traj;
  114. return new SO.Molecule.Trajectory(traj, { label: a.label, description: a.description });
  115. });
  116. }
  117. });
  118. export const LoadG3D = StateAction.build({
  119. display: { name: 'Load Genome 3D (G3D)', description: 'Load G3D file from the specified URL.' },
  120. from: SO.Root,
  121. params: { url: ParamDefinition.Text('') }
  122. })(({ params, state }, ctx: PluginContext) => Task.create('Genome3D', taskCtx => {
  123. return state.transaction(async () => {
  124. if (params.url.trim().length === 0) {
  125. throw new Error('Specify URL');
  126. }
  127. ctx.behaviors.layout.leftPanelTabName.next('data');
  128. const trajectory = await state.build().toRoot()
  129. .apply(G3DHeaderFromUrl, { url: params.url })
  130. .apply(G3DTrajectory)
  131. .commit();
  132. await defaultStructure(ctx, { trajectory });
  133. }).runInContext(taskCtx);
  134. }));
  135. export const G3DFormat = PluginBehavior.create<{ autoAttach: boolean, showTooltip: boolean }>({
  136. name: 'g3d',
  137. category: 'misc',
  138. display: {
  139. name: 'G3D',
  140. description: 'G3D Format Support'
  141. },
  142. ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean, showTooltip: boolean }> {
  143. register() {
  144. this.ctx.state.data.actions.add(LoadG3D);
  145. objectForEach(G3dSymbols, s => DefaultQueryRuntimeTable.addSymbol(s));
  146. this.ctx.managers.lociLabels.addProvider(G3dLabelProvider);
  147. }
  148. unregister() {
  149. this.ctx.state.data.actions.remove(LoadG3D);
  150. objectForEach(G3dSymbols, s => DefaultQueryRuntimeTable.removeSymbol(s));
  151. this.ctx.managers.lociLabels.removeProvider(G3dLabelProvider);
  152. }
  153. }
  154. });