Skip to content
Snippets Groups Projects
Commit 25734028 authored by Alexander Rose's avatar Alexander Rose
Browse files

wip, color list refactoring

parent e769d77e
No related branches found
No related tags found
No related merge requests found
......@@ -19,7 +19,7 @@ function paramInfo(param: PD.Any, offset: number): string {
case 'conditioned': return getParams(param.conditionParams, offset);
case 'multi-select': return `Array of ${oToS(param.options)}`;
case 'color': return 'Color as 0xrrggbb';
case 'color-scale': return `One of ${oToS(param.options)}`;
case 'color-list': return `One of ${oToS(param.options)}`;
case 'vec3': return `3D vector [x, y, z]`;
case 'file': return `JavaScript File Handle`;
case 'select': return `One of ${oToS(param.options)}`;
......
......@@ -81,7 +81,7 @@ export namespace DirectVolume {
Vec2.create(0.19, 0.0), Vec2.create(0.2, 0.05), Vec2.create(0.25, 0.05), Vec2.create(0.26, 0.0),
Vec2.create(0.79, 0.0), Vec2.create(0.8, 0.05), Vec2.create(0.85, 0.05), Vec2.create(0.86, 0.0),
]),
list: PD.ColorScale<ColorListName>('red-yellow-blue', ColorListOptions),
list: PD.ColorList<ColorListName>('red-yellow-blue', ColorListOptions),
}
export type Params = typeof Params
......
......@@ -7,8 +7,8 @@
import { Vec2, Vec3 } from '../../../mol-math/linear-algebra';
import { Color } from '../../../mol-util/color';
import { ColorListName, getColorListFromName } from '../../../mol-util/color/scale';
import { ColorNames, ColorNamesValueMap } from '../../../mol-util/color/tables';
import { ColorListName, getColorListFromName } from '../../../mol-util/color/lists';
import { ColorNames, ColorNamesValueMap } from '../../../mol-util/color/names';
import { memoize1 } from '../../../mol-util/memoize';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { camelCaseToWords } from '../../../mol-util/string';
......@@ -54,7 +54,7 @@ function controlFor(param: PD.Any): ParamControl | undefined {
case 'conditioned': return ConditionedControl;
case 'multi-select': return MultiSelectControl;
case 'color': return ColorControl;
case 'color-scale': return ColorScaleControl;
case 'color-list': return ColorListControl;
case 'vec3': return Vec3Control;
case 'file': return FileControl;
case 'select': return SelectControl;
......@@ -298,14 +298,35 @@ export class ColorControl extends SimpleParam<PD.Color> {
}
}
const colorScaleGradient = memoize1((n: ColorListName) => `linear-gradient(to right, ${getColorListFromName(n).map(c => Color.toStyle(c)).join(', ')})`);
const colorGradientInterpolated = memoize1((colors: Color[]) => {
const styles = colors.map(c => Color.toStyle(c))
return `linear-gradient(to right, ${styles.join(', ')})`
});
const colorGradientBanded = memoize1((colors: Color[]) => {
const n = colors.length
const styles: string[] = [`${Color.toStyle(colors[0])} ${100 * (1 / n)}%`]
for (let i = 1, il = n - 1; i < il; ++i) {
styles.push(
`${Color.toStyle(colors[i])} ${100 * (i / n)}%`,
`${Color.toStyle(colors[i])} ${100 * ((i + 1) / n)}%`
)
}
styles.push(`${Color.toStyle(colors[n - 1])} ${100 * ((n - 1) / n)}%`)
return `linear-gradient(to right, ${styles.join(', ')})`
});
function colorGradient(name: ColorListName, banded: boolean) {
const { list, type } = getColorListFromName(name)
return type === 'qualitative' ? colorGradientBanded(list) : colorGradientInterpolated(list)
}
export class ColorScaleControl extends SimpleParam<PD.ColorScale<any>> {
export class ColorListControl extends SimpleParam<PD.ColorList<any>> {
onChange = (e: React.ChangeEvent<HTMLSelectElement>) => { this.update(e.target.value); }
stripStyle(): React.CSSProperties {
return {
background: colorScaleGradient(this.props.value),
background: colorGradient(this.props.value, true),
position: 'absolute',
bottom: '0',
height: '4px',
......
......@@ -11,14 +11,14 @@ import { ColorTheme, LocationColor } from '../color';
import { Vec3 } from '../../mol-math/linear-algebra';
import { ParamDefinition as PD } from '../../mol-util/param-definition'
import { ThemeDataContext } from '../../mol-theme/theme';
import { ColorListName, ColorListOptions } from '../../mol-util/color/lists';
import { ColorListName, ColorListOptionsScale } from '../../mol-util/color/lists';
const DefaultColor = Color(0xCCCCCC)
const Description = 'Colors cross-links by the deviation of the observed distance versus the modeled distance (e.g. `ihm_cross_link_restraint.distance_threshold`).'
export const CrossLinkColorThemeParams = {
domain: PD.Interval([-10, 10]),
list: PD.ColorScale<ColorListName>('red-grey', ColorListOptions),
list: PD.ColorList<ColorListName>('red-grey', ColorListOptionsScale),
}
export type CrossLinkColorThemeParams = typeof CrossLinkColorThemeParams
export function getCrossLinkColorThemeParams(ctx: ThemeDataContext) {
......
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ColorScale, Color } from '../../mol-util/color';
import { Color } from '../../mol-util/color';
import { Location } from '../../mol-model/location';
import { StructureElement, Link } from '../../mol-model/structure';
import { OrderedSet } from '../../mol-data/int';
import { ColorTheme, LocationColor } from '../color';
import { ParamDefinition as PD } from '../../mol-util/param-definition'
import { ThemeDataContext } from '../../mol-theme/theme';
import { ColorListOptions, ColorListName } from '../../mol-util/color/lists';
import { getPaletteParams, getPalette } from './util';
import { TableLegend } from '../../mol-util/color/lists';
import { ScaleLegend } from '../../mol-util/color/scale';
const DefaultColor = Color(0xCCCCCC)
const Description = 'Gives every element (atom or coarse sphere/gaussian) a unique color based on the position (index) of the element in the list of elements in the structure.'
export const ElementIndexColorThemeParams = {
list: PD.ColorScale<ColorListName>('red-yellow-blue', ColorListOptions),
...getPaletteParams({ scaleList: 'red-yellow-blue' }),
}
export type ElementIndexColorThemeParams = typeof ElementIndexColorThemeParams
export function getElementIndexColorThemeParams(ctx: ThemeDataContext) {
......@@ -26,7 +28,7 @@ export function getElementIndexColorThemeParams(ctx: ThemeDataContext) {
export function ElementIndexColorTheme(ctx: ThemeDataContext, props: PD.Values<ElementIndexColorThemeParams>): ColorTheme<ElementIndexColorThemeParams> {
let color: LocationColor
let scale = ColorScale.create({ listOrName: props.list, minLabel: 'Start', maxLabel: 'End' })
let legend: ScaleLegend | TableLegend | undefined
if (ctx.structure) {
const { units } = ctx.structure
......@@ -40,17 +42,18 @@ export function ElementIndexColorTheme(ctx: ThemeDataContext, props: PD.Values<E
elementCount += units[i].elements.length
unitIdIndex.set(units[i].id, i)
}
scale.setDomain(0, elementCount - 1)
const scaleColor = scale.color
const palette = getPalette(elementCount, props)
legend = palette.legend
color = (location: Location): Color => {
if (StructureElement.isLocation(location)) {
const unitIndex = unitIdIndex.get(location.unit.id)!
const unitElementIndex = OrderedSet.findPredecessorIndex(location.unit.elements, location.element)
return scaleColor(cummulativeElementCount.get(unitIndex)! + unitElementIndex)
return palette.color(cummulativeElementCount.get(unitIndex)! + unitElementIndex)
} else if (Link.isLocation(location)) {
const unitIndex = unitIdIndex.get(location.aUnit.id)!
return scaleColor(cummulativeElementCount.get(unitIndex)! + location.aIndex)
return palette.color(cummulativeElementCount.get(unitIndex)! + location.aIndex)
}
return DefaultColor
}
......@@ -64,7 +67,7 @@ export function ElementIndexColorTheme(ctx: ThemeDataContext, props: PD.Values<E
color,
props,
description: Description,
legend: scale ? scale.legend : undefined
legend
}
}
......
......@@ -11,12 +11,12 @@ import { ColorTheme } from '../color';
import { ParamDefinition as PD } from '../../mol-util/param-definition'
import { ThemeDataContext } from '../theme';
import { ResidueHydrophobicity } from '../../mol-model/structure/model/types';
import { ColorListName, ColorListOptions } from '../../mol-util/color/lists';
import { ColorListName, ColorListOptionsScale } from '../../mol-util/color/lists';
const Description = 'Assigns a color to every amino acid according to the "Experimentally determined hydrophobicity scale for proteins at membrane interfaces" by Wimely and White (doi:10.1038/nsb1096-842).'
export const HydrophobicityColorThemeParams = {
list: PD.ColorScale<ColorListName>('red-yellow-green', ColorListOptions),
list: PD.ColorList<ColorListName>('red-yellow-green', ColorListOptionsScale),
scale: PD.Select('DGwif', [['DGwif', 'DG water-membrane'], ['DGwoct', 'DG water-octanol'], ['Oct-IF', 'DG difference']])
}
export type HydrophobicityColorThemeParams = typeof HydrophobicityColorThemeParams
......
......@@ -11,13 +11,13 @@ import { Location } from '../../mol-model/location';
import { ColorTheme } from '../color';
import { ParamDefinition as PD } from '../../mol-util/param-definition'
import { ThemeDataContext } from '../../mol-theme/theme';
import { ColorListOptions, ColorListName } from '../../mol-util/color/lists';
import { ColorListOptionsScale, ColorListName } from '../../mol-util/color/lists';
const DefaultColor = Color(0xCCCCCC)
const Description = 'Gives every polymer residue a color based on its `seq_id` value.'
export const SequenceIdColorThemeParams = {
list: PD.ColorScale<ColorListName>('rainbow', ColorListOptions),
list: PD.ColorList<ColorListName>('rainbow', ColorListOptionsScale),
}
export type SequenceIdColorThemeParams = typeof SequenceIdColorThemeParams
export function getSequenceIdColorThemeParams(ctx: ThemeDataContext) {
......
......@@ -10,14 +10,14 @@ import { Location } from '../../mol-model/location';
import { ColorTheme } from '../color';
import { ParamDefinition as PD } from '../../mol-util/param-definition'
import { ThemeDataContext } from '../theme';
import { ColorListName, ColorListOptions } from '../../mol-util/color/lists';
import { ColorListName, ColorListOptionsScale } from '../../mol-util/color/lists';
const DefaultUncertaintyColor = Color(0xffff99)
const Description = `Assigns a color based on the uncertainty of an element's position, , e.g. B-factor or RMSF, depending on the data availability and experimental technique.`
export const UncertaintyColorThemeParams = {
domain: PD.Interval([0, 100]),
list: PD.ColorScale<ColorListName>('red-white-blue', ColorListOptions),
list: PD.ColorList<ColorListName>('red-white-blue', ColorListOptionsScale),
}
export type UncertaintyColorThemeParams = typeof UncertaintyColorThemeParams
export function getUncertaintyColorThemeParams(ctx: ThemeDataContext) {
......
......@@ -21,10 +21,10 @@ export function getPaletteParams(props: Partial<GetPaletteProps> = {}) {
return {
palette: PD.MappedStatic('generate', {
scale: PD.Group({
list: PD.ColorScale<ColorListName>(p.scaleList, ColorListOptionsScale),
list: PD.ColorList<ColorListName>(p.scaleList, ColorListOptionsScale),
}, { isFlat: true }),
set: PD.Group({
list: PD.ColorScale<ColorListName>(p.setList, ColorListOptionsSet),
list: PD.ColorList<ColorListName>(p.setList, ColorListOptionsSet),
}, { isFlat: true }),
generate: PD.Group({
...DistinctColorsParams,
......@@ -32,7 +32,7 @@ export function getPaletteParams(props: Partial<GetPaletteProps> = {}) {
}, { isFlat: true })
}, {
options: [
['scale', 'From Scale'],
['scale', 'Interpolate'],
['set', 'From Set'],
['generate', 'Generate Distinct']
]
......@@ -62,7 +62,7 @@ export function getPalette(count: number, props: PaletteProps) {
let colors: Color[]
if (props.palette.name === 'set') {
const listOrName = props.palette.params.list
colors = typeof listOrName === 'string' ? getColorListFromName(listOrName) : listOrName
colors = typeof listOrName === 'string' ? getColorListFromName(listOrName).list : listOrName
} else {
count = Math.min(count, props.palette.params.maxCount)
colors = distinctColors(count, props.palette.params)
......
......@@ -125,7 +125,7 @@ export const ColorLists = {
'',
[0x67001f, 0xb2182b, 0xd6604d, 0xf4a582, 0xfddbc7, 0xffffff, 0xe0e0e0, 0xbababa, 0x878787, 0x4d4d4d, 0x1a1a1a]
),
'purple-orange': ColorList('Purple-Orange', 'diverging',
'orange-purple': ColorList('Orange-Purple', 'diverging',
'',
[0x7f3b08, 0xb35806, 0xe08214, 0xfdb863, 0xfee0b6, 0xf7f7f7, 0xd8daeb, 0xb2abd2, 0x8073ac, 0x542788, 0x2d004b]
),
......@@ -209,7 +209,7 @@ export const ColorListOptionsScale = ColorListOptions.filter(v => ColorLists[v[0
export const ColorListOptionsSet = ColorListOptions.filter(v => ColorLists[v[0]].type === 'qualitative')
export function getColorListFromName(name: ColorListName) {
if (name in ColorLists) return ColorLists[name as ColorListName].list
if (name in ColorLists) return ColorLists[name as ColorListName]
console.warn(`unknown color list named '${name}'`)
return ColorLists['red-yellow-blue'].list
return ColorLists['red-yellow-blue']
}
......@@ -44,7 +44,7 @@ export type ColorScaleProps = Partial<typeof DefaultColorScaleProps>
export namespace ColorScale {
export function create(props: ColorScaleProps): ColorScale {
const { domain, reverse, listOrName } = { ...DefaultColorScaleProps, ...props }
const list = typeof listOrName === 'string' ? getColorListFromName(listOrName) : listOrName
const list = typeof listOrName === 'string' ? getColorListFromName(listOrName).list : listOrName
const colors = reverse ? list.slice().reverse() : list
const count1 = colors.length - 1
......
......@@ -62,13 +62,13 @@ export namespace ParamDefinition {
return setInfo<Select<T>>({ type: 'select', defaultValue, options }, info)
}
export interface ColorScale<T extends string> extends Base<T> {
type: 'color-scale'
export interface ColorList<T extends string> extends Base<T> {
type: 'color-list'
/** array of (value, label) tuples */
options: [T, string][]
}
export function ColorScale<T extends string>(defaultValue: T, options: [T, string][], info?: Info): ColorScale<T> {
return setInfo<ColorScale<T>>({ type: 'color-scale', defaultValue, options }, info)
export function ColorList<T extends string>(defaultValue: T, options: [T, string][], info?: Info): ColorList<T> {
return setInfo<ColorList<T>>({ type: 'color-list', defaultValue, options }, info)
}
export interface MultiSelect<E extends string, T = E[]> extends Base<T> {
......@@ -242,7 +242,7 @@ export namespace ParamDefinition {
export type Any =
| Value<any> | Select<any> | MultiSelect<any> | BooleanParam | Text | Color | Vec3 | Numeric | FileParam | Interval | LineGraph
| ColorScale<any> | Group<any> | Mapped<any> | Converted<any, any> | Conditioned<any, any, any> | ScriptExpression | ObjectList
| ColorList<any> | Group<any> | Mapped<any> | Converted<any, any> | Conditioned<any, any, any> | ScriptExpression | ObjectList
export type Params = { [k: string]: Any }
export type Values<T extends Params> = { [k in keyof T]: T[k]['defaultValue'] }
......
......@@ -101,7 +101,7 @@ 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)
list: PD.ColorList<ColorListName>('rainbow', ColorListOptions)
}
export type AccessibleSurfaceAreaColorThemeParams = typeof AccessibleSurfaceAreaColorThemeParams
export function getAccessibleSurfaceAreaColorThemeParams(ctx: ThemeDataContext) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment