unipept-visualizations
Version:
The Unipept visualisation library
89 lines (77 loc) • 3.41 kB
text/typescript
import HeatmapFeature from "./HeatmapFeature";
import HeatmapValue from "./HeatmapValue";
import * as d3 from "d3";
export default class Preprocessor {
/**
* Converts an array of feature labels into correct HeatmapFeature objects. These objects keep track of a name
* and index for a feature.
*
* @param featureLabels All labels that should be converted to true HeatmapFeature objects.
* @return An array with HeatmapFeature objects.
*/
preprocessFeatures(featureLabels: string[]): HeatmapFeature[] {
return Object.entries(featureLabels).map(([idx, feature]) => {
return {
name: feature,
idx: Number.parseInt(idx)
}
});
}
/**
* Convert the data grid consisting of numbers into valid HeatmapValue-objects. The order from the input grid is
* retained in the output grid. A color will be computed for each distinct value. Only a specific amount of colors
* will be generated, as determined by the colorValues parameter.
*
* @param data A grid of numbers that needs to be converted to proper HeatmapValue-objects.
* @param lowColor Color value that should be used for low values
* @param highColor Color value that should be used for high values
* @param colorValues How many discrete color values should be generated?
* @return A two-dimensional grid of HeatmapValue objects.
*/
preprocessValues(
data: (number | HeatmapValue)[][],
lowColor: string,
highColor: string,
colorValues: number
): HeatmapValue[][] {
const interpolator = d3.interpolateLab(d3.lab(lowColor), d3.lab(highColor));
const x = d3.scaleLinear().domain([0, 1]).range([0, 1]);
const ticks = x.ticks(colorValues);
const quantizeScale = d3.scaleQuantize().domain([0, 1]).range(ticks);
return Object.entries(data).map(([rowIdx, row]) => Object.entries(row).map(([colIdx, value]) => {
if (typeof value === "number") {
const quantizedValue = quantizeScale(value);
if (quantizedValue === undefined) {
throw new Error("Invalid heatmap value given: " + value);
}
return {
value: value as number,
rowId: Number.parseInt(rowIdx),
columnId: Number.parseInt(colIdx),
color: interpolator(quantizedValue)
};
} else {
return value;
}
}));
}
/**
* Order all values in a map, per color.
*
* @param values All grid values for which we should determine a color.
* @return A mapping between an HTML-color value and a list of [row, col] positions.
*/
orderPerColor(values: HeatmapValue[][]): Map<string, [number, number][]> {
const output = new Map<string, [number, number][]>();
for (let rowIdx = 0; rowIdx < values.length; rowIdx++) {
for (let colIdx = 0; colIdx < values[rowIdx].length; colIdx++) {
const colorString = values[rowIdx][colIdx].color;
if (!output.has(colorString)) {
output.set(colorString, []);
}
output.get(colorString)?.push([rowIdx, colIdx]);
}
}
return output;
}
}