Browse Source

focus color theme for alignments

bioinsilico 1 year ago
parent
commit
fd81caac95

+ 8 - 1
CHANGELOG.md

@@ -2,11 +2,18 @@
 
 [Semantic Versioning](https://semver.org/)
 
+## [3.0.11] - 2023-08-10
+### Improvements
+- New focus color theme to match the ribbon color in alignment views
+
+### Dependency update
+- molstar v3.38.3
+
 ## [3.0.10] - 2023-07-11
 ### Bug fix
 - Change sequence chain in Assembly view bug fixed
  
-- ### Dependency update
+### Dependency update
 - rcsb-api-tools v4.1.13,
 - rcsb-saguaro v2.5.13,
 - rcsb-saguaro-app v5.0.8

+ 23 - 23
package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "@rcsb/rcsb-saguaro-3d",
-  "version": "3.0.9",
+  "version": "3.0.10",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "@rcsb/rcsb-saguaro-3d",
-      "version": "3.0.9",
+      "version": "3.0.10",
       "license": "MIT",
       "dependencies": {
         "@rcsb/rcsb-api-tools": "^4.1.13",
@@ -56,7 +56,7 @@
       },
       "peerDependencies": {
         "@rcsb/rcsb-molstar": "^2.7.1",
-        "molstar": "^3.37.1"
+        "molstar": "^3.38.3"
       }
     },
     "../rcsb-saguaro-app": {
@@ -10082,16 +10082,16 @@
       "peer": true
     },
     "node_modules/molstar": {
-      "version": "3.37.1",
-      "resolved": "https://registry.npmjs.org/molstar/-/molstar-3.37.1.tgz",
-      "integrity": "sha512-AeXhWQEyomoysLY0VYxXBuNPAmR5nx06JkfuNurBDI6gRnYrZ/ro96Xo6cA7Ew4KQwKuaAjviBafYzOSdw/DEg==",
+      "version": "3.38.3",
+      "resolved": "https://registry.npmjs.org/molstar/-/molstar-3.38.3.tgz",
+      "integrity": "sha512-O6ET+a/Cbq3xiHZ3vE1toUgbAz5/IJGNMVD0HbevKAStMsZ1pZZOiLQeIb7tD7eFvrtjJsMRSzTkLgLa3OvYMg==",
       "peer": true,
       "dependencies": {
         "@types/argparse": "^2.0.10",
         "@types/benchmark": "^2.1.2",
         "@types/compression": "1.7.2",
         "@types/express": "^4.17.17",
-        "@types/node": "^16.18.35",
+        "@types/node": "^16.18.38",
         "@types/node-fetch": "^2.6.4",
         "@types/swagger-ui-dist": "3.30.1",
         "argparse": "^2.0.1",
@@ -10102,10 +10102,10 @@
         "h264-mp4-encoder": "^1.0.12",
         "immer": "^9.0.21",
         "immutable": "^4.3.0",
-        "node-fetch": "^2.6.11",
+        "node-fetch": "^2.6.12",
         "rxjs": "^7.8.1",
-        "swagger-ui-dist": "^4.19.0",
-        "tslib": "^2.5.3",
+        "swagger-ui-dist": "^5.1.0",
+        "tslib": "^2.6.0",
         "util.promisify": "^1.1.2",
         "xhr2": "^0.2.1"
       },
@@ -12841,9 +12841,9 @@
       }
     },
     "node_modules/swagger-ui-dist": {
-      "version": "4.19.1",
-      "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.19.1.tgz",
-      "integrity": "sha512-n/gFn+R7G/BXWwl5UZLw6F1YgWOlf3zkwGlsPhTMhNtAAolBGKg0JS5b2RKt5NI6/hSopVaSrki2wTIMUDDy2w==",
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.3.1.tgz",
+      "integrity": "sha512-El78OvXp9zMasfPrshtkW1CRx8AugAKoZuGGOTW+8llJzOV1RtDJYqQRz/6+2OakjeWWnZuRlN2Qj1Y0ilux3w==",
       "peer": true
     },
     "node_modules/swap-case": {
@@ -22054,16 +22054,16 @@
       "peer": true
     },
     "molstar": {
-      "version": "3.37.1",
-      "resolved": "https://registry.npmjs.org/molstar/-/molstar-3.37.1.tgz",
-      "integrity": "sha512-AeXhWQEyomoysLY0VYxXBuNPAmR5nx06JkfuNurBDI6gRnYrZ/ro96Xo6cA7Ew4KQwKuaAjviBafYzOSdw/DEg==",
+      "version": "3.38.3",
+      "resolved": "https://registry.npmjs.org/molstar/-/molstar-3.38.3.tgz",
+      "integrity": "sha512-O6ET+a/Cbq3xiHZ3vE1toUgbAz5/IJGNMVD0HbevKAStMsZ1pZZOiLQeIb7tD7eFvrtjJsMRSzTkLgLa3OvYMg==",
       "peer": true,
       "requires": {
         "@types/argparse": "^2.0.10",
         "@types/benchmark": "^2.1.2",
         "@types/compression": "1.7.2",
         "@types/express": "^4.17.17",
-        "@types/node": "^16.18.35",
+        "@types/node": "^16.18.38",
         "@types/node-fetch": "^2.6.4",
         "@types/swagger-ui-dist": "3.30.1",
         "argparse": "^2.0.1",
@@ -22076,11 +22076,11 @@
         "immer": "^9.0.21",
         "immutable": "^4.3.0",
         "jpeg-js": "^0.4.4",
-        "node-fetch": "^2.6.11",
+        "node-fetch": "^2.6.12",
         "pngjs": "^6.0.0",
         "rxjs": "^7.8.1",
-        "swagger-ui-dist": "^4.19.0",
-        "tslib": "^2.5.3",
+        "swagger-ui-dist": "^5.1.0",
+        "tslib": "^2.6.0",
         "util.promisify": "^1.1.2",
         "xhr2": "^0.2.1"
       },
@@ -24109,9 +24109,9 @@
       "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
     },
     "swagger-ui-dist": {
-      "version": "4.19.1",
-      "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.19.1.tgz",
-      "integrity": "sha512-n/gFn+R7G/BXWwl5UZLw6F1YgWOlf3zkwGlsPhTMhNtAAolBGKg0JS5b2RKt5NI6/hSopVaSrki2wTIMUDDy2w==",
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.3.1.tgz",
+      "integrity": "sha512-El78OvXp9zMasfPrshtkW1CRx8AugAKoZuGGOTW+8llJzOV1RtDJYqQRz/6+2OakjeWWnZuRlN2Qj1Y0ilux3w==",
       "peer": true
     },
     "swap-case": {

+ 2 - 2
package.json

@@ -1,6 +1,6 @@
 {
   "name": "@rcsb/rcsb-saguaro-3d",
-  "version": "3.0.10",
+  "version": "3.0.11",
   "description": "RCSB Molstar/Saguaro Web App",
   "main": "build/dist/app.js",
   "files": [
@@ -93,7 +93,7 @@
   },
   "peerDependencies": {
     "@rcsb/rcsb-molstar": "^2.7.1",
-    "molstar": "^3.37.1"
+    "molstar": "^3.38.3"
   },
   "bugs": {
     "url": "https://github.com/rcsb/rcsb-saguaro-3d/issues"

+ 12 - 0
src/RcsbFvStructure/StructureViewers/MolstarViewer/TrajectoryPresetProvider/AlignmentRepresentationPresetProvider.ts

@@ -43,6 +43,8 @@ import {StructureRepresentationBuilder} from "molstar/lib/mol-plugin-state/build
 import {RigidTransformType, TransformMatrixType} from "../../../StructureUtils/StructureLoaderInterface";
 import {StateTransform} from "molstar/lib/mol-state/transform";
 import {TransformStructureConformation} from "molstar/lib/mol-plugin-state/transforms/model";
+import updateFocusRepr = StructureRepresentationPresetProvider.updateFocusRepr;
+import {FOCUS_RESIDUE_COLOR} from "./FocusTheme/FocusColoring";
 
 type RepresentationParamsType = {
     pdb?:{entryId:string;entityId:string;}|{entryId:string;instanceId:string;};
@@ -144,6 +146,7 @@ export const AlignmentRepresentationPresetProvider = StructureRepresentationPres
                     type: "cartoon"
                 });
 
+
                 await update.commit({ revertOnError: false });
                 break;
             }
@@ -233,6 +236,15 @@ export const AlignmentRepresentationPresetProvider = StructureRepresentationPres
             if(comp && expression.tag != "water") anyLigComp = comp;
         }
 
+        structure.inheritedPropertyData.reprList = Object.values(representationMap).filter(repr=>typeof repr != "undefined");
+        await updateFocusRepr(
+            plugin,
+            structure,
+            FOCUS_RESIDUE_COLOR,
+            {}
+        );
+
+
         return {
             components: componentMap,
             representations: representationMap

+ 6 - 4
src/RcsbFvStructure/StructureViewers/MolstarViewer/TrajectoryPresetProvider/AlignmentTrajectoryPresetProvider.ts

@@ -7,14 +7,14 @@ import {TrajectoryHierarchyPresetProvider} from "molstar/lib/mol-plugin-state/bu
 import {PluginContext} from "molstar/lib/mol-plugin/context";
 import {PluginStateObject} from "molstar/lib/mol-plugin-state/objects";
 import {ParamDefinition, ParamDefinition as PD} from "molstar/lib/mol-util/param-definition";
-import {StateObjectRef, StateObjectSelector} from "molstar/lib/mol-state";
+import {StateObjectRef} from "molstar/lib/mol-state";
 import {RootStructureDefinition} from "molstar/lib/mol-plugin-state/helpers/root-structure";
-import {StateTransformer} from "molstar/lib/mol-state/transformer";
 import {StateObject} from "molstar/lib/mol-state/object";
 import {AlignmentRepresentationPresetProvider} from "./AlignmentRepresentationPresetProvider";
 import {TargetAlignment} from "@rcsb/rcsb-api-tools/build/RcsbGraphQL/Types/Borrego/GqlTypes";
 import {Structure, StructureElement, StructureProperties as SP} from "molstar/lib/mol-model/structure";
 import {RigidTransformType} from "../../../StructureUtils/StructureLoaderInterface";
+import {FocusResidueColorThemeProvider} from "./FocusTheme/FocusColoring";
 
 
 export type AlignmentTrajectoryParamsType = {
@@ -24,8 +24,6 @@ export type AlignmentTrajectoryParamsType = {
     modelIndex?: number;
 }
 
-type StructureObject = StateObjectSelector<PluginStateObject.Molecule.Structure, StateTransformer<StateObject<any, StateObject.Type<any>>, StateObject<any, StateObject.Type<any>>, any>>
-
 export const AlignmentTrajectoryPresetProvider = TrajectoryHierarchyPresetProvider({
     id: 'alignment-to-reference',
     display: {
@@ -77,6 +75,10 @@ export const AlignmentTrajectoryPresetProvider = TrajectoryHierarchyPresetProvid
         }while(!entityCheck);
 
         const structureProperties = await builder.insertStructureProperties(structure);
+
+        if (!plugin.representation.structure.themes.colorThemeRegistry.has(FocusResidueColorThemeProvider))
+            plugin.representation.structure.themes.colorThemeRegistry.add(FocusResidueColorThemeProvider);
+
         const representation = await plugin.builders.structure.representation.applyPreset(
             structureProperties,
             AlignmentRepresentationPresetProvider,

+ 96 - 0
src/RcsbFvStructure/StructureViewers/MolstarViewer/TrajectoryPresetProvider/FocusTheme/FocusColoring.ts

@@ -0,0 +1,96 @@
+import {
+    Bond,
+    StructureElement,
+    StructureProperties, Unit
+} from 'molstar/lib/mol-model/structure';
+import { Color } from 'molstar/lib/mol-util/color';
+import { ThemeDataContext } from 'molstar/lib/mol-theme/theme';
+import { ParamDefinition } from 'molstar/lib/mol-util/param-definition';
+import { ColorTheme } from 'molstar/lib/mol-theme/color';
+import { Location } from 'molstar/lib/mol-model/location';
+import {Overpaint} from "molstar/lib/commonjs/mol-theme/overpaint";
+import Layer = Overpaint.Layer;
+import {OrderedSet} from "molstar/lib/mol-data/int";
+import {
+    ElementSymbolColorTheme,
+    ElementSymbolColorThemeParams,
+    getElementSymbolColorThemeParams
+} from "molstar/lib/mol-theme/color/element-symbol";
+
+export const FOCUS_RESIDUE_COLOR = 'focus-residue-color' as ColorTheme.BuiltIn;
+export function FocusResidueColorTheme(ctx: ThemeDataContext, props: ParamDefinition.Values<ElementSymbolColorThemeParams>): ColorTheme<{}> {
+
+    const L = StructureElement.Location.create();
+
+    const bondColor = (location: StructureElement.Location) => {
+        for(const repr of ctx.structure?.inheritedPropertyData.reprList){
+            const layer: Layer = repr.obj.data.repr.state.overpaint.layers.find((layer: Layer)=>{
+                if(!StructureElement.Loci.is(layer.loci))
+                    return false;
+                return isLocationInLoci(location, layer.loci);
+            });
+            if(layer)
+                return layer.color;
+        }
+        return ctx.structure?.inheritedPropertyData.reprList[0].obj.data.repr.theme.color.color(location);
+    };
+
+    const nonCarbonAtomsColor = ElementSymbolColorTheme(ctx, props).color as (location: Location) => Color
+    const atomColor = (location: StructureElement.Location)=> {
+        if(location.unit.model.atomicHierarchy.atoms.type_symbol.value(location.element) == 'C')
+            return bondColor(location);
+        return nonCarbonAtomsColor(location);
+    };
+
+    const color = (location: Location) => {
+        if (StructureElement.Location.is(location) && Unit.isAtomic(location.unit)) {
+            return atomColor(location);
+        } else if (Bond.isLocation(location)) {
+            L.structure = location.aStructure;
+            L.unit = location.aUnit;
+            L.element = location.aUnit.elements[location.aIndex];
+            return bondColor(L);
+        }
+        return Color(0x777777);
+    };
+
+    return {
+        factory: FocusResidueColorTheme,
+        granularity: 'group',
+        color,
+        props
+    };
+
+}
+export const FocusResidueColorThemeProvider = {
+    name: FOCUS_RESIDUE_COLOR,
+    label: 'Focus Residue',
+    category: ColorTheme.Category.Misc,
+    factory: FocusResidueColorTheme,
+    getParams: getElementSymbolColorThemeParams,
+    defaultValues: ParamDefinition.getDefaultValues(ElementSymbolColorThemeParams),
+    isApplicable: () => true,
+};
+
+function isLocationInLoci(location: StructureElement.Location, loci: StructureElement.Loci): boolean {
+    const modelId = location.structure.model.id;
+    const seqId = StructureProperties.residue.label_seq_id(location);
+    const asymId = StructureProperties.chain.label_asym_id(location);
+
+    const currentLoci = loci;
+    const loc: StructureElement.Location = StructureElement.Location.create(currentLoci.structure);
+    const layerModelId = loc.structure.model.id
+    for(let n = 0; n < OrderedSet.size(currentLoci.elements[0].indices); n++){
+        StructureElement.Location.set(
+            loc,
+            currentLoci.structure,
+            currentLoci.elements[0].unit,
+            currentLoci.elements[0].unit.elements[OrderedSet.getAt(currentLoci.elements[0].indices,n)]
+        );
+        const layerSeqId = StructureProperties.residue.label_seq_id(loc);
+        const layerAsymId = StructureProperties.chain.label_asym_id(loc);
+        if(modelId == layerModelId && asymId == layerAsymId && seqId == layerSeqId)
+            return true;
+    }
+    return false;
+}

+ 4 - 3
src/examples/uniprot/index.ts

@@ -3,11 +3,12 @@ import {RcsbFv3DUniprot} from "../../RcsbFv3D/RcsbFv3DUniprot";
 
 document.addEventListener("DOMContentLoaded", function(event) {
 
+    const upAcc = "Q06124";
     const panel3d = new RcsbFv3DUniprot({
         config:{
-            upAcc:"P01112",
-            title: "Title >> Uniprot P01112",
-            subtitle: "Subtitle >> Uniprot P01112",
+            upAcc,
+            title: "Title >> Uniprot " + upAcc,
+            subtitle: "Subtitle >> Uniprot " + upAcc,
         }
     });
     panel3d.render();