Browse Source

default coloring improvments

- changed chain-id theme to assign distinct color accros the whole scene
- made chain-id the default
- added 'many-distinct' color list
- changed element-symbol theme to use cahin-id theme for carbon coloring
- indicate focus repr with translucent halo
Alexander Rose 4 years ago
parent
commit
f4cb3aeed7

+ 2 - 2
src/mol-plugin-state/builder/structure/representation-preset.ts

@@ -123,11 +123,11 @@ const polymerAndLigand = StructureRepresentationPresetProvider({
         const representations = {
             polymer: builder.buildRepresentation(update, components.polymer, { type: 'cartoon', typeParams: { ...typeParams, ...cartoonProps }, color }, { tag: 'polymer' }),
             ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams, color }, { tag: 'ligand' }),
-            nonStandard: builder.buildRepresentation(update, components.nonStandard, { type: 'ball-and-stick', typeParams, color: color || 'polymer-id' }, { tag: 'non-standard' }),
+            nonStandard: builder.buildRepresentation(update, components.nonStandard, { type: 'ball-and-stick', typeParams, color }, { tag: 'non-standard' }),
             branchedBallAndStick: builder.buildRepresentation(update, components.branched, { type: 'ball-and-stick', typeParams: { ...typeParams, alpha: 0.3 }, color }, { tag: 'branched-ball-and-stick' }),
             branchedSnfg3d: builder.buildRepresentation(update, components.branched, { type: 'carbohydrate', typeParams, color }, { tag: 'branched-snfg-3d' }),
             water: builder.buildRepresentation(update, components.water, { type: 'ball-and-stick', typeParams: { ...typeParams, alpha: 0.6 }, color }, { tag: 'water' }),
-            coarse: builder.buildRepresentation(update, components.coarse, { type: 'spacefill', typeParams, color: color || 'polymer-id' }, { tag: 'coarse' })
+            coarse: builder.buildRepresentation(update, components.coarse, { type: 'spacefill', typeParams, color: color || 'chain-id' }, { tag: 'coarse' })
         };
 
         await update.commit({ revertOnError: false });

+ 2 - 3
src/mol-plugin/behavior/dynamic/selection/structure-focus-representation.ts

@@ -18,7 +18,6 @@ import { SizeTheme } from '../../../../mol-theme/size';
 import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
 import { PluginCommands } from '../../../commands';
 import { PluginContext } from '../../../context';
-import { Color } from '../../../../mol-util/color';
 
 const StructureFocusRepresentationParams = (plugin: PluginContext) => {
     const reprParams = StateTransforms.Representation.StructureRepresentation3D.definition.params!(void 0, plugin) as PD.Params;
@@ -26,11 +25,11 @@ const StructureFocusRepresentationParams = (plugin: PluginContext) => {
         expandRadius: PD.Numeric(5, { min: 1, max: 10, step: 1 }),
         targetParams: PD.Group(reprParams, {
             label: 'Target',
-            customDefault: createStructureRepresentationParams(plugin, void 0, { type: 'ball-and-stick', size: 'physical', typeParams: { sizeFactor: 0.17 }, colorParams: { carbon: Color.fromRgb(100, 100, 100) } })
+            customDefault: createStructureRepresentationParams(plugin, void 0, { type: 'ball-and-stick', size: 'physical', typeParams: { sizeFactor: 0.26, alpha: 0.51 } })
         }),
         surroundingsParams: PD.Group(reprParams, {
             label: 'Surroundings',
-            customDefault: createStructureRepresentationParams(plugin, void 0, { type: 'ball-and-stick', color: 'element-symbol', size: 'physical', typeParams: { sizeFactor: 0.16 }, colorParams: { carbon: Color.fromRgb(160, 160, 160) } })
+            customDefault: createStructureRepresentationParams(plugin, void 0, { type: 'ball-and-stick', color: 'element-symbol', size: 'physical', typeParams: { sizeFactor: 0.16 } })
         }),
         nciParams: PD.Group(reprParams, {
             label: 'Non-covalent Int.',

+ 1 - 1
src/mol-repr/structure/representation/cartoon.ts

@@ -63,7 +63,7 @@ export const CartoonRepresentationProvider = StructureRepresentationProvider({
     factory: CartoonRepresentation,
     getParams: getCartoonParams,
     defaultValues: PD.getDefaultValues(CartoonParams),
-    defaultColorTheme: { name: 'polymer-id' },
+    defaultColorTheme: { name: 'chain-id' },
     defaultSizeTheme: { name: 'uniform' },
     isApplicable: (structure: Structure) => structure.polymerResidueCount > 0,
     ensureCustomProperties: {

+ 1 - 1
src/mol-repr/structure/representation/gaussian-surface.ts

@@ -42,7 +42,7 @@ export const GaussianSurfaceRepresentationProvider = StructureRepresentationProv
     factory: GaussianSurfaceRepresentation,
     getParams: getGaussianSurfaceParams,
     defaultValues: PD.getDefaultValues(GaussianSurfaceParams),
-    defaultColorTheme: { name: 'polymer-id' },
+    defaultColorTheme: { name: 'chain-id' },
     defaultSizeTheme: { name: 'uniform' },
     isApplicable: (structure: Structure) => structure.elementCount > 0
 });

+ 1 - 1
src/mol-repr/structure/representation/gaussian-volume.ts

@@ -35,7 +35,7 @@ export const GaussianVolumeRepresentationProvider = StructureRepresentationProvi
     factory: GaussianVolumeRepresentation,
     getParams: getGaussianVolumeParams,
     defaultValues: PD.getDefaultValues(GaussianVolumeParams),
-    defaultColorTheme: { name: 'polymer-id' },
+    defaultColorTheme: { name: 'chain-id' },
     defaultSizeTheme: { name: 'uniform' },
     isApplicable: (structure: Structure) => structure.elementCount > 0
 });

+ 1 - 1
src/mol-repr/structure/representation/molecular-surface.ts

@@ -40,7 +40,7 @@ export const MolecularSurfaceRepresentationProvider = StructureRepresentationPro
     factory: MolecularSurfaceRepresentation,
     getParams: getMolecularSurfaceParams,
     defaultValues: PD.getDefaultValues(MolecularSurfaceParams),
-    defaultColorTheme: { name: 'polymer-id' },
+    defaultColorTheme: { name: 'chain-id' },
     defaultSizeTheme: { name: 'uniform' },
     isApplicable: (structure: Structure) => structure.elementCount > 0
 });

+ 1 - 1
src/mol-repr/structure/representation/orientation.ts

@@ -37,7 +37,7 @@ export const OrientationRepresentationProvider = StructureRepresentationProvider
     factory: OrientationRepresentation,
     getParams: getOrientationParams,
     defaultValues: PD.getDefaultValues(OrientationParams),
-    defaultColorTheme: { name: 'polymer-id' },
+    defaultColorTheme: { name: 'chain-id' },
     defaultSizeTheme: { name: 'uniform' },
     isApplicable: (structure: Structure) => structure.elementCount > 0
 });

+ 1 - 1
src/mol-repr/structure/representation/putty.ts

@@ -50,7 +50,7 @@ export const PuttyRepresentationProvider = StructureRepresentationProvider({
     factory: PuttyRepresentation,
     getParams: getPuttyParams,
     defaultValues: PD.getDefaultValues(PuttyParams),
-    defaultColorTheme: { name: 'polymer-id' },
+    defaultColorTheme: { name: 'chain-id' },
     defaultSizeTheme: { name: 'uncertainty' },
     isApplicable: (structure: Structure) => structure.polymerResidueCount > 0
 });

+ 37 - 45
src/mol-theme/color/chain-id.ts

@@ -1,10 +1,10 @@
 /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { Unit, StructureProperties, StructureElement, Bond, Structure } from '../../mol-model/structure';
+import { Unit, StructureProperties, StructureElement, Bond, Structure, Model } from '../../mol-model/structure';
 import { Color } from '../../mol-util/color';
 import { Location } from '../../mol-model/location';
 import { ColorTheme, LocationColor } from '../color';
@@ -12,66 +12,58 @@ import { ParamDefinition as PD } from '../../mol-util/param-definition';
 import { ThemeDataContext } from '../../mol-theme/theme';
 import { getPaletteParams, getPalette } from '../../mol-util/color/palette';
 import { TableLegend, ScaleLegend } from '../../mol-util/legend';
-import { Segmentation } from '../../mol-data/int';
-import { ColorLists, getColorListFromName } from '../../mol-util/color/lists';
 
-const DefaultList = 'dark-2';
+const DefaultList = 'many-distinct';
 const DefaultColor = Color(0xFAFAFA);
 const Description = 'Gives every chain a color based on its `asym_id` value.';
 
 export const ChainIdColorThemeParams = {
+    asymId: PD.Select('auth', PD.arrayToOptions<AsymIdType>(['auth', 'label'])),
     ...getPaletteParams({ type: 'colors', colorList: DefaultList }),
 };
 export type ChainIdColorThemeParams = typeof ChainIdColorThemeParams
 export function getChainIdColorThemeParams(ctx: ThemeDataContext) {
     const params = PD.clone(ChainIdColorThemeParams);
-    if (ctx.structure) {
-        if (getAsymIdSerialMap(ctx.structure.root).size > ColorLists[DefaultList].list.length) {
-            params.palette.defaultValue.name = 'colors';
-            params.palette.defaultValue.params = {
-                ...params.palette.defaultValue.params,
-                list: { kind: 'interpolate', colors: getColorListFromName(DefaultList).list }
-            };
-        }
-    }
     return params;
 }
 
-function getAsymId(unit: Unit): StructureElement.Property<string> {
+type AsymIdType = 'auth' | 'label';
+
+function getAsymId(unit: Unit, type: AsymIdType): StructureElement.Property<string> {
     switch (unit.kind) {
         case Unit.Kind.Atomic:
-            return StructureProperties.chain.label_asym_id;
+            return type === 'auth'
+                ? StructureProperties.chain.auth_asym_id
+                : StructureProperties.chain.label_asym_id;
         case Unit.Kind.Spheres:
         case Unit.Kind.Gaussians:
             return StructureProperties.coarse.asym_id;
     }
 }
 
-function getAsymIdSerialMap(structure: Structure) {
+function getAsymIdKey(location: StructureElement.Location, type: AsymIdType) {
+    const asymId = getAsymId(location.unit, type)(location);
+    return location.structure.models.length > 1
+        ? getKey(location.unit.model, asymId)
+        : asymId;
+}
+
+function getKey(model: Model, asymId: string) {
+    return `${asymId} | ${(Model.Index.get(model).value || 0) + 1}`;
+}
+
+function getAsymIdSerialMap(structure: Structure, type: AsymIdType) {
     const map = new Map<string, number>();
-    for (let i = 0, il = structure.unitSymmetryGroups.length; i < il; ++i) {
-        const unit = structure.unitSymmetryGroups[i].units[0];
-        const { model } = unit;
-        if (Unit.isAtomic(unit)) {
-            const { chainAtomSegments, chains } = model.atomicHierarchy;
-            const chainIt = Segmentation.transientSegments(chainAtomSegments, unit.elements);
-            while (chainIt.hasNext) {
-                const { index: chainIndex } = chainIt.move();
-                const asymId = chains.label_asym_id.value(chainIndex);
-                if (!map.has(asymId)) map.set(asymId, map.size);
-            }
-        } else if (Unit.isCoarse(unit)) {
-            const { chainElementSegments, asym_id } = Unit.isSpheres(unit)
-                ? model.coarseHierarchy.spheres
-                : model.coarseHierarchy.gaussians;
-            const chainIt = Segmentation.transientSegments(chainElementSegments, unit.elements);
-            while (chainIt.hasNext) {
-                const { index: chainIndex } = chainIt.move();
-                const elementIndex = chainElementSegments.offsets[chainIndex];
-                const asymId = asym_id.value(elementIndex);
-                if (!map.has(asymId)) map.set(asymId, map.size);
-            }
-        }
+    for (const m of structure.models) {
+        const asymIdOffset = Model.AsymIdOffset.get(m).value;
+        const offset = (type === 'auth' ? asymIdOffset?.auth : asymIdOffset?.label) || 0;
+        m.properties.structAsymMap.forEach(({ auth_id }, label_id) => {
+            const asymId = type === 'auth' ? auth_id : label_id;
+            const k = structure.models.length > 1
+                ? getKey(m, asymId)
+                : asymId;
+            if (!map.has(k)) map.set(k, map.size + offset);
+        });
     }
     return map;
 }
@@ -82,7 +74,7 @@ export function ChainIdColorTheme(ctx: ThemeDataContext, props: PD.Values<ChainI
 
     if (ctx.structure) {
         const l = StructureElement.Location.create(ctx.structure);
-        const asymIdSerialMap = getAsymIdSerialMap(ctx.structure.root);
+        const asymIdSerialMap = getAsymIdSerialMap(ctx.structure.root, props.asymId);
 
         const labelTable = Array.from(asymIdSerialMap.keys());
         props.palette.params.valueLabel = (i: number) => labelTable[i];
@@ -93,13 +85,13 @@ export function ChainIdColorTheme(ctx: ThemeDataContext, props: PD.Values<ChainI
         color = (location: Location): Color => {
             let serial: number | undefined = undefined;
             if (StructureElement.Location.is(location)) {
-                const asym_id = getAsymId(location.unit);
-                serial = asymIdSerialMap.get(asym_id(location));
+                const k = getAsymIdKey(location, props.asymId);
+                serial = asymIdSerialMap.get(k);
             } else if (Bond.isLocation(location)) {
-                const asym_id = getAsymId(location.aUnit);
                 l.unit = location.aUnit;
                 l.element = location.aUnit.elements[location.aIndex];
-                serial = asymIdSerialMap.get(asym_id(l));
+                const k = getAsymIdKey(l, props.asymId);
+                serial = asymIdSerialMap.get(k);
             }
             return serial === undefined ? DefaultColor : palette.color(serial);
         };

+ 14 - 7
src/mol-theme/color/element-symbol.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -13,6 +13,7 @@ import { ParamDefinition as PD } from '../../mol-util/param-definition';
 import { ThemeDataContext } from '../theme';
 import { TableLegend } from '../../mol-util/legend';
 import { getAdjustedColorMap } from '../../mol-util/color/color';
+import { ChainIdColorTheme, getChainIdColorThemeParams } from './chain-id';
 
 // from Jmol http://jmol.sourceforge.net/jscolors/ (or 0xFFFFFF)
 export const ElementSymbolColors = ColorMap({
@@ -24,9 +25,9 @@ const DefaultElementSymbolColor = Color(0xFFFFFF);
 const Description = 'Assigns a color to every atom according to its chemical element.';
 
 export const ElementSymbolColorThemeParams = {
-    carbon: PD.Color(ElementSymbolColors.C),
+    carbonByChainId: PD.Boolean(true),
     saturation: PD.Numeric(0, { min: -6, max: 6, step: 0.1 }),
-    lightness: PD.Numeric(0.7, { min: -6, max: 6, step: 0.1 })
+    lightness: PD.Numeric(0.2, { min: -6, max: 6, step: 0.1 })
 };
 export type ElementSymbolColorThemeParams = typeof ElementSymbolColorThemeParams
 export function getElementSymbolColorThemeParams(ctx: ThemeDataContext) {
@@ -40,20 +41,26 @@ export function elementSymbolColor(colorMap: ElementSymbolColors, element: Eleme
 
 export function ElementSymbolColorTheme(ctx: ThemeDataContext, props: PD.Values<ElementSymbolColorThemeParams>): ColorTheme<ElementSymbolColorThemeParams> {
     const colorMap = getAdjustedColorMap(ElementSymbolColors, props.saturation, props.lightness);
-    const carbonColor = Color.darken(Color.saturate(props.carbon, props.saturation), -props.lightness);
+
+    const chainIdColor = ChainIdColorTheme(ctx, PD.getDefaultValues(getChainIdColorThemeParams(ctx))).color;
+
+    function elementColor(element: ElementSymbol, location: Location) {
+        return (props.carbonByChainId && element === 'C')
+            ? chainIdColor(location, false)
+            : elementSymbolColor(colorMap, element);
+    }
 
     function color(location: Location): Color {
         if (StructureElement.Location.is(location)) {
             if (Unit.isAtomic(location.unit)) {
                 const { type_symbol } = location.unit.model.atomicHierarchy.atoms;
-                const element = type_symbol.value(location.element);
-                return element === 'C' ? carbonColor : elementSymbolColor(colorMap, element);
+                return elementColor(type_symbol.value(location.element), location);
             }
         } else if (Bond.isLocation(location)) {
             if (Unit.isAtomic(location.aUnit)) {
                 const { type_symbol } = location.aUnit.model.atomicHierarchy.atoms;
                 const element = type_symbol.value(location.aUnit.elements[location.aIndex]);
-                return element === 'C' ? carbonColor : elementSymbolColor(colorMap, element);
+                return elementColor(element, location);
             }
         }
         return DefaultElementSymbolColor;

+ 12 - 0
src/mol-util/color/lists.ts

@@ -155,6 +155,18 @@ export const ColorLists = {
         [0xfbb4ae, 0xb3cde3, 0xccebc5, 0xdecbe4, 0xfed9a6, 0xffffcc, 0xe5d8bd, 0xfddaec, 0xf2f2f2]
     ),
 
+    'many-distinct': ColorList('Many-Distinct', 'qualitative',
+        '',
+        [
+            // dark-2
+            0x1b9e77, 0xd95f02, 0x7570b3, 0xe7298a, 0x66a61e, 0xe6ab02, 0xa6761d, 0x666666,
+            // set-1
+            0xe41a1c, 0x377eb8, 0x4daf4a, 0x984ea3, 0xff7f00, 0xffff33, 0xa65628, 0xf781bf, 0x999999,
+            // set-2
+            0x66c2a5, 0xfc8d62, 0x8da0cb, 0xe78ac3, 0xa6d854, 0xffd92f, 0xe5c494, 0xb3b3b3
+        ]
+    ),
+
     /**
      * Matplotlib colormaps, including various perceptually uniform shades, see https://bids.github.io/colormap/
      */