|
@@ -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);
|
|
|
};
|