mirror of
https://github.com/getredash/redash.git
synced 2026-03-22 19:00:09 -04:00
* getredash/redash#2629 Refactor Chart visualization, add option for handling NULL values (keep/convert to 0.0) * Handle null values in line/area stacking code; some cleanup * Handle edge case: line/area stacking when last value of one of series is missing * Mjnor update to line/area stacking code * Fix line/area normalize to percents feature * Unit tests * Refine tests; add tests for prepareLayout function * Tests for prepareData (heatmap) function * Tests for prepareData (pie) function * Tests for prepareData (bar, line, area) function * Tests for prepareData (scatter, bubble) function * Tests for prepareData (box) function * Remove unused file
110 lines
2.7 KiB
JavaScript
110 lines
2.7 KiB
JavaScript
import { map, max, uniq, sortBy, flatten, find } from 'lodash';
|
|
import { createNumberFormatter } from '@/lib/value-format';
|
|
|
|
const defaultColorScheme = [
|
|
[0, '#356aff'],
|
|
[0.14, '#4a7aff'],
|
|
[0.28, '#5d87ff'],
|
|
[0.42, '#7398ff'],
|
|
[0.56, '#fb8c8c'],
|
|
[0.71, '#ec6463'],
|
|
[0.86, '#ec4949'],
|
|
[1, '#e92827'],
|
|
];
|
|
|
|
function prepareSeries(series, options, additionalOptions) {
|
|
const { colorScheme, formatNumber } = additionalOptions;
|
|
|
|
const plotlySeries = {
|
|
x: [],
|
|
y: [],
|
|
z: [],
|
|
type: 'heatmap',
|
|
name: '',
|
|
colorscale: colorScheme,
|
|
};
|
|
|
|
plotlySeries.x = uniq(map(series.data, v => v.x));
|
|
plotlySeries.y = uniq(map(series.data, v => v.y));
|
|
|
|
if (options.sortX) {
|
|
plotlySeries.x = sortBy(plotlySeries.x);
|
|
}
|
|
|
|
if (options.sortY) {
|
|
plotlySeries.y = sortBy(plotlySeries.y);
|
|
}
|
|
|
|
if (options.reverseX) {
|
|
plotlySeries.x.reverse();
|
|
}
|
|
|
|
if (options.reverseY) {
|
|
plotlySeries.y.reverse();
|
|
}
|
|
|
|
const zMax = max(map(series.data, d => d.zVal));
|
|
|
|
// Use text trace instead of default annotation for better performance
|
|
const dataLabels = {
|
|
x: [],
|
|
y: [],
|
|
mode: 'text',
|
|
hoverinfo: 'skip',
|
|
showlegend: false,
|
|
text: [],
|
|
textfont: {
|
|
color: [],
|
|
},
|
|
};
|
|
|
|
for (let i = 0; i < plotlySeries.y.length; i += 1) {
|
|
const item = [];
|
|
for (let j = 0; j < plotlySeries.x.length; j += 1) {
|
|
const datum = find(
|
|
series.data,
|
|
{ x: plotlySeries.x[j], y: plotlySeries.y[i] },
|
|
);
|
|
|
|
const zValue = datum && datum.zVal || 0;
|
|
item.push(zValue);
|
|
|
|
if (isFinite(zMax) && options.showDataLabels) {
|
|
dataLabels.x.push(plotlySeries.x[j]);
|
|
dataLabels.y.push(plotlySeries.y[i]);
|
|
dataLabels.text.push(formatNumber(zValue));
|
|
if (options.colorScheme && options.colorScheme === 'Custom...') {
|
|
dataLabels.textfont.color.push('white');
|
|
} else {
|
|
dataLabels.textfont.color.push((zValue / zMax) < 0.25 ? 'white' : 'black');
|
|
}
|
|
}
|
|
}
|
|
plotlySeries.z.push(item);
|
|
}
|
|
|
|
if (isFinite(zMax) && options.showDataLabels) {
|
|
return [plotlySeries, dataLabels];
|
|
}
|
|
return [plotlySeries];
|
|
}
|
|
|
|
export default function prepareHeatmapData(seriesList, options) {
|
|
let colorScheme = [];
|
|
|
|
if (!options.colorScheme) {
|
|
colorScheme = defaultColorScheme;
|
|
} else if (options.colorScheme === 'Custom...') {
|
|
colorScheme = [[0, options.heatMinColor], [1, options.heatMaxColor]];
|
|
} else {
|
|
colorScheme = options.colorScheme;
|
|
}
|
|
|
|
const additionalOptions = {
|
|
colorScheme,
|
|
formatNumber: createNumberFormatter(options.numberFormat),
|
|
};
|
|
|
|
return flatten(map(seriesList, series => prepareSeries(series, options, additionalOptions)));
|
|
}
|