import { isNil, extend, each, includes, map, sortBy } from 'lodash'; import chooseTextColorForBackground from '@/lib/chooseTextColorForBackground'; import { ColorPaletteArray } from '@/visualizations/ColorPalette'; import { cleanNumber, normalizeValue, getSeriesAxis } from './utils'; function getSeriesColor(seriesOptions, seriesIndex) { return seriesOptions.color || ColorPaletteArray[seriesIndex % ColorPaletteArray.length]; } function getHoverInfoPattern(options) { const hasX = /{{\s*@@x\s*}}/.test(options.textFormat); const hasName = /{{\s*@@name\s*}}/.test(options.textFormat); let result = 'text'; if (!hasX) result += '+x'; if (!hasName) result += '+name'; return result; } function prepareBarSeries(series, options) { series.type = 'bar'; if (options.showDataLabels) { series.textposition = 'inside'; } return series; } function prepareLineSeries(series, options) { series.mode = 'lines' + (options.showDataLabels ? '+text' : ''); return series; } function prepareAreaSeries(series, options) { series.mode = 'lines' + (options.showDataLabels ? '+text' : ''); series.fill = options.series.stacking ? 'tonexty' : 'tozeroy'; return series; } function prepareScatterSeries(series, options) { series.type = 'scatter'; series.mode = 'markers' + (options.showDataLabels ? '+text' : ''); return series; } function prepareBubbleSeries(series, options, { seriesColor, data }) { series.mode = 'markers'; series.marker = { color: seriesColor, size: map(data, i => i.size), }; return series; } function prepareBoxSeries(series, options, { seriesColor }) { series.type = 'box'; series.mode = 'markers'; series.boxpoints = 'outliers'; series.hoverinfo = false; series.marker = { color: seriesColor, size: 3, }; if (options.showpoints) { series.boxpoints = 'all'; series.jitter = 0.3; series.pointpos = -1.8; } return series; } function prepareSeries(series, options, additionalOptions) { const { hoverInfoPattern, index } = additionalOptions; const seriesOptions = extend( { type: options.globalSeriesType, yAxis: 0 }, options.seriesOptions[series.name], ); const seriesColor = getSeriesColor(seriesOptions, index); const seriesYAxis = getSeriesAxis(series, options); // Sort by x - `Map` preserves order of items const data = options.sortX ? sortBy(series.data, d => normalizeValue(d.x, options.xAxis.type)) : series.data; // For bubble/scatter charts `y` may be any (similar to `x`) - numeric is only bubble size; // for other types `y` is always number const cleanYValue = includes(['bubble', 'scatter'], seriesOptions.type) ? normalizeValue : (v) => { v = cleanNumber(v); return (options.missingValuesAsZero && isNil(v)) ? 0.0 : v; }; const sourceData = new Map(); const xValues = []; const yValues = []; const yErrorValues = []; each(data, (row) => { const x = normalizeValue(row.x, options.xAxis.type); // number/datetime/category const y = cleanYValue(row.y, seriesYAxis === 'y2' ? options.yAxis[1].type : options.yAxis[0].type); // depends on series type! const yError = cleanNumber(row.yError); // always number const size = cleanNumber(row.size); // always number sourceData.set(x, { x, y, yError, size, yPercent: null, // will be updated later row, }); xValues.push(x); yValues.push(y); yErrorValues.push(yError); }); const plotlySeries = { visible: true, hoverinfo: hoverInfoPattern, x: xValues, y: yValues, error_y: { array: yErrorValues, color: seriesColor, }, name: seriesOptions.name || series.name, marker: { color: seriesColor }, insidetextfont: { color: chooseTextColorForBackground(seriesColor), }, yaxis: seriesYAxis, sourceData, }; additionalOptions = { ...additionalOptions, seriesColor, data }; switch (seriesOptions.type) { case 'column': return prepareBarSeries(plotlySeries, options, additionalOptions); case 'line': return prepareLineSeries(plotlySeries, options, additionalOptions); case 'area': return prepareAreaSeries(plotlySeries, options, additionalOptions); case 'scatter': return prepareScatterSeries(plotlySeries, options, additionalOptions); case 'bubble': return prepareBubbleSeries(plotlySeries, options, additionalOptions); case 'box': return prepareBoxSeries(plotlySeries, options, additionalOptions); default: return plotlySeries; } } export default function prepareDefaultData(seriesList, options) { const additionalOptions = { hoverInfoPattern: getHoverInfoPattern(options), }; return map(seriesList, (series, index) => prepareSeries(series, options, { ...additionalOptions, index })); }