diff --git a/giraffe/package.json b/giraffe/package.json index 7013a255..a3e3720a 100644 --- a/giraffe/package.json +++ b/giraffe/package.json @@ -1,6 +1,6 @@ { "name": "@influxdata/giraffe", - "version": "2.8.2", + "version": "2.9.0", "main": "dist/index.js", "module": "src/index.js", "license": "MIT", diff --git a/giraffe/src/components/StaticLegendBox.tsx b/giraffe/src/components/StaticLegendBox.tsx index 70206afc..29606b36 100644 --- a/giraffe/src/components/StaticLegendBox.tsx +++ b/giraffe/src/components/StaticLegendBox.tsx @@ -53,11 +53,17 @@ export const StaticLegendBox: FunctionComponent = props => const layerConfig = configOverride.layers[staticLegendOverride.layer] const valueColumnKey = layerConfig[staticLegendOverride.valueAxis] + const position = Array.isArray( + (spec as LineLayerSpec).stackedDomainValueColumn + ) + ? 'stacked' + : 'overlaid' const legendData = convertLineSpec( staticLegendOverride, spec as LineLayerSpec, columnFormatter, - valueColumnKey + valueColumnKey, + position ) const { legendBackgroundColor: backgroundColor, diff --git a/giraffe/src/transforms/line.ts b/giraffe/src/transforms/line.ts index 1ec324ec..7875beac 100644 --- a/giraffe/src/transforms/line.ts +++ b/giraffe/src/transforms/line.ts @@ -1,15 +1,17 @@ import { CumulativeValuesByTime, DomainLabel, + LatestIndexMap, LineData, LineLayerSpec, LinePosition, NumericColumnData, Table, } from '../types' -import {FILL, VALUE} from '../constants/columnKeys' +import {FILL, TIME, VALUE} from '../constants/columnKeys' import {createGroupIDColumn, getNominalColorScale} from './' import {getDomainDataFromLines} from '../utils/lineData' +import {isDefined} from '../utils/isDefined' export const mapCumulativeValuesToTimeRange = ( timesCol: NumericColumnData, @@ -73,6 +75,7 @@ export const lineTransform = ( const fillScale = getNominalColorScale(fillColumnMap, colors) const lineData: LineData = {} let stackedValuesByTime: CumulativeValuesByTime = {} + const latestIndices: LatestIndexMap = {} if (position === 'stacked') { if (yColumnKey === VALUE) { @@ -114,6 +117,23 @@ export const lineTransform = ( lineData[groupID].xs.push(x) lineData[groupID].ys.push(y) + // remember the latest (most recent) index for each group + if (!isDefined(latestIndices[groupID])) { + latestIndices[groupID] = i + } else if (yColumnKey === TIME) { + if ( + y > yCol[latestIndices[groupID]] || + !isDefined(yCol[latestIndices[groupID]]) + ) { + latestIndices[groupID] = i + } + } else if ( + x > xCol[latestIndices[groupID]] || + !isDefined(xCol[latestIndices[groupID]]) + ) { + latestIndices[groupID] = i + } + if (x < xMin) { xMin = x } @@ -139,7 +159,6 @@ export const lineTransform = ( ) } - //todo: look at stackdomainvalue column for stacked data for static legend return { type: 'line', inputTable, @@ -152,7 +171,7 @@ export const lineTransform = ( xColumnType: table.getColumnType(xColumnKey), yColumnType: table.getColumnType(yColumnKey), scales: {fill: fillScale}, - columnGroupMaps: {fill: fillColumnMap}, + columnGroupMaps: {fill: fillColumnMap, latestIndices}, stackedDomainValueColumn, } } diff --git a/giraffe/src/types/index.ts b/giraffe/src/types/index.ts index f67370bc..b487ad02 100644 --- a/giraffe/src/types/index.ts +++ b/giraffe/src/types/index.ts @@ -622,6 +622,7 @@ export interface LineLayerSpec { } columnGroupMaps: { fill: ColumnGroupMap + latestIndices: LatestIndexMap } stackedDomainValueColumn?: NumericColumnData } @@ -807,6 +808,15 @@ export interface ColumnGroupMap { mappings: Array<{[columnKey: string]: any}> } +export interface LatestIndexMap { + // each Column in a Table contains a single array even when there are multiple series + // for example, a line graph has multiple lines (series), but each Column has only one array + // Static Legend needs to know where each line (series) ends, to render the "latest" + // - "latest" is the timestamp with the highest value in each line (series) + // - Keep a map of the highest timestamp's index for each series + [columnKey: string]: number +} + export type LineData = { [groupID: number]: { xs: number[] diff --git a/giraffe/src/utils/fixtures/legend.ts b/giraffe/src/utils/fixtures/randomTable.ts similarity index 96% rename from giraffe/src/utils/fixtures/legend.ts rename to giraffe/src/utils/fixtures/randomTable.ts index a6855410..c2570889 100644 --- a/giraffe/src/utils/fixtures/legend.ts +++ b/giraffe/src/utils/fixtures/randomTable.ts @@ -2,16 +2,6 @@ import {newTable} from '../newTable' import {LayerTypes} from '../../types' import memoizeOne from 'memoize-one' -interface SampleTableOptions { - include_negative?: boolean - all_negative?: boolean - decimalPlaces?: number - maxValue?: number - numberOfRecords?: number - recordsPerLine?: number - plotType?: string -} - const getRandomNumber = ( max: number, decimalPlaces: number, @@ -28,55 +18,6 @@ export const COLUMN_KEY = 'cpu' export const POINT_KEY = 'disk' export const HOST_KEY = 'host' -export const createSampleTable = (options: SampleTableOptions) => { - const { - include_negative = false, - all_negative = false, - decimalPlaces = 2, - maxValue = 100, - numberOfRecords = 20, - recordsPerLine = 5, - plotType = 'line', - } = options - - const now = Date.now() - const TIME_COL = [] - const VALUE_COL = [] - const CPU_COL = [] - const SYMBOL_COL = [] - const DISK_COL = [] - const HOST_COL = [] - - for (let i = 0; i < numberOfRecords; i += 1) { - let num = getRandomNumber(maxValue, decimalPlaces) - if (include_negative) { - num = all_negative - ? Math.abs(num) * -1 - : getRandomNumber(maxValue, decimalPlaces, true) - } - VALUE_COL.push(num) - CPU_COL.push(`${COLUMN_KEY}${Math.floor(i / recordsPerLine)}`) - TIME_COL.push(now + (i % recordsPerLine) * 1000 * 60) - if (plotType === LayerTypes.Scatter) { - SYMBOL_COL.push(i % 2) - DISK_COL.push(`disk-${i % recordsPerLine}`) - HOST_COL.push(`host-${i % 2}`) - } - } - const table = newTable(numberOfRecords) - .addColumn('_time', 'dateTime:RFC3339', 'time', TIME_COL) - .addColumn('_value', 'system', 'number', VALUE_COL) - - if (plotType === LayerTypes.Scatter) { - return table - .addColumn(POINT_KEY, 'string', 'string', DISK_COL) - .addColumn('__symbol', 'string', 'string', SYMBOL_COL) - .addColumn(HOST_KEY, 'string', 'string', HOST_COL) - } - return table.addColumn(COLUMN_KEY, 'string', 'string', CPU_COL) -} - -const now = Date.now() const defaultNumberOfRecords = 80 const defaultRecordsPerLine = 20 @@ -100,6 +41,7 @@ interface RandomFillColumns { export const getRandomTable = memoizeOne( ( maxValue: number, + includeNegative: boolean, numberOfRecords: number = defaultNumberOfRecords, recordsPerLine: number = defaultRecordsPerLine, fillColumns?: ColumnsArg, @@ -112,9 +54,10 @@ export const getRandomTable = memoizeOne( columnNames: [], columnValues: [], } as RandomFillColumns + const now = Date.now() for (let i = 0; i < numberOfRecords; i += 1) { - valueColumn.push(getRandomNumber(maxValue, 2)) + valueColumn.push(getRandomNumber(maxValue, 2, includeNegative)) cpuColumn.push(`cpu${Math.floor(i / recordsPerLine)}`) timeColumn.push(now + (i % recordsPerLine) * 1000 * 60) } @@ -173,3 +116,61 @@ export const getRandomTable = memoizeOne( return table } ) + +export interface SampleTableOptions { + include_negative?: boolean + all_negative?: boolean + decimalPlaces?: number + maxValue?: number + numberOfRecords?: number + recordsPerLine?: number + plotType?: string +} + +export const createSampleTable = (options: SampleTableOptions) => { + const { + include_negative = false, + all_negative = false, + decimalPlaces = 2, + maxValue = 100, + numberOfRecords = 20, + recordsPerLine = 5, + plotType = 'line', + } = options + + const now = Date.now() + const TIME_COL = [] + const VALUE_COL = [] + const CPU_COL = [] + const SYMBOL_COL = [] + const DISK_COL = [] + const HOST_COL = [] + + for (let i = 0; i < numberOfRecords; i += 1) { + let num = getRandomNumber(maxValue, decimalPlaces) + if (include_negative) { + num = all_negative + ? Math.abs(num) * -1 + : getRandomNumber(maxValue, decimalPlaces, true) + } + VALUE_COL.push(num) + CPU_COL.push(`${COLUMN_KEY}${Math.floor(i / recordsPerLine)}`) + TIME_COL.push(now + (i % recordsPerLine) * 1000 * 60) + if (plotType === LayerTypes.Scatter) { + SYMBOL_COL.push(i % 2) + DISK_COL.push(`disk-${i % recordsPerLine}`) + HOST_COL.push(`host-${i % 2}`) + } + } + const table = newTable(numberOfRecords) + .addColumn('_time', 'dateTime:RFC3339', 'time', TIME_COL) + .addColumn('_value', 'system', 'number', VALUE_COL) + + if (plotType === LayerTypes.Scatter) { + return table + .addColumn(POINT_KEY, 'string', 'string', DISK_COL) + .addColumn('__symbol', 'string', 'string', SYMBOL_COL) + .addColumn(HOST_KEY, 'string', 'string', HOST_COL) + } + return table.addColumn(COLUMN_KEY, 'string', 'string', CPU_COL) +} diff --git a/giraffe/src/utils/legend/sort.test.ts b/giraffe/src/utils/legend/sort.test.ts new file mode 100644 index 00000000..47f47a8a --- /dev/null +++ b/giraffe/src/utils/legend/sort.test.ts @@ -0,0 +1,77 @@ +import {getDataSortOrder} from './sort' +import {getRandomTable} from '../fixtures/randomTable' +import {lineTransform} from '../../transforms/line' +import {NINETEEN_EIGHTY_FOUR} from '../../constants/colorSchemes' +import {DomainLabel} from '../../types' + +describe('getDataSortOrder', () => { + const xColKey = '_time' + const yColKey = '_value' + const maxValue = 100 + const numberOfRecords = 200 + const recordsPerLine = 10 + const fillColKeys = ['cpu', 'host', 'machine'] + const table = getRandomTable( + maxValue, + true, + numberOfRecords, + recordsPerLine, + fillColKeys + ) + + it('leaves overlaid line graphs unsorted', () => { + const lineOption = 'overlaid' + const lineSpec = lineTransform( + table, + xColKey, + yColKey, + fillColKeys, + NINETEEN_EIGHTY_FOUR, + lineOption + ) + + const latestIndices = Object.values(lineSpec.columnGroupMaps.latestIndices) + const sortOrder = getDataSortOrder( + lineSpec.lineData, + latestIndices, + lineOption, + DomainLabel.Y + ) + expect(latestIndices).toEqual(sortOrder) + }) + + it('sorts stacked line graphs in descending order', () => { + const lineOption = 'stacked' + const lineSpec = lineTransform( + table, + xColKey, + yColKey, + fillColKeys, + NINETEEN_EIGHTY_FOUR, + lineOption + ) + const {stackedDomainValueColumn} = lineSpec + + const latestIndices = Object.values(lineSpec.columnGroupMaps.latestIndices) + const sortOrder = getDataSortOrder( + lineSpec.lineData, + latestIndices, + lineOption, + DomainLabel.Y + ) + expect(sortOrder.length).toBeGreaterThanOrEqual(2) + sortOrder.forEach((columnIndex, index) => { + if (index < sortOrder.length - 1) { + expect( + stackedDomainValueColumn[columnIndex] > + stackedDomainValueColumn[columnIndex + 1] + ) + } else { + expect( + stackedDomainValueColumn[columnIndex] < + stackedDomainValueColumn[columnIndex + 1] + ) + } + }) + }) +}) diff --git a/giraffe/src/utils/legend/sort.ts b/giraffe/src/utils/legend/sort.ts new file mode 100644 index 00000000..cc034f3c --- /dev/null +++ b/giraffe/src/utils/legend/sort.ts @@ -0,0 +1,31 @@ +import {DomainLabel, LineData, LinePosition} from '../../types' + +export const getDataSortOrder = ( + lineData: LineData, + rowIndices: number[], + position: LinePosition, + domainLabel?: DomainLabel +): number[] => { + if (!position || position === 'overlaid') { + return rowIndices + } + + const domainLabelName = domainLabel || DomainLabel.Y + + const numberMap = {} + const numericalValues = Object.keys(lineData).reduce( + (combinedNumericalValues, id) => + combinedNumericalValues.concat(lineData[id][domainLabelName]), + [] + ) + const sortable = [] + rowIndices.forEach(rowIndex => { + if (!numberMap[numericalValues[rowIndex]]) { + numberMap[numericalValues[rowIndex]] = [] + } + numberMap[numericalValues[rowIndex]].push(rowIndex) + sortable.push(numericalValues[rowIndex]) + }) + sortable.sort((first, second) => second - first) + return sortable.map(numericalValue => numberMap[numericalValue].shift()) +} diff --git a/giraffe/src/utils/legend/staticLegend.test.ts b/giraffe/src/utils/legend/staticLegend.test.ts index 0fd32f95..1c87444b 100644 --- a/giraffe/src/utils/legend/staticLegend.test.ts +++ b/giraffe/src/utils/legend/staticLegend.test.ts @@ -2,43 +2,80 @@ import {convertLineSpec} from './staticLegend' import {NINETEEN_EIGHTY_FOUR} from '../../constants/colorSchemes' import {STATIC_LEGEND_DEFAULTS} from '../../constants/index' import {lineTransform} from '../../transforms/line' -import {getRandomTable} from '../fixtures/legend' +import {getRandomTable} from '../fixtures/randomTable' describe('convertLineSpec', () => { - it('convertLineSpec', () => { - const xColKey = '_time' - const yColKey = '_value' - const getColumnFormatter = () => (x: string) => x - const maxValue = 100 - const numberOfRecords = 20 - const recordsPerLine = 5 - const fillColumnKeys = ['cpu', 'host', 'machine'] - const sampleTable = getRandomTable( - maxValue, - numberOfRecords, - recordsPerLine, - fillColumnKeys - ) + const xColKey = '_time' + const yColKey = '_value' + const getColumnFormatter = () => (x: string) => x + const maxValue = 100 + const numberOfRecords = 20 + const recordsPerLine = 5 + const fillColumnKeys = ['cpu', 'host', 'machine'] + const sampleTable = getRandomTable( + maxValue, + false, + numberOfRecords, + recordsPerLine, + fillColumnKeys + ) + + it('creates certain columns for overlaid line graphs', () => { + const position = 'overlaid' const lineSpec = lineTransform( sampleTable, xColKey, yColKey, fillColumnKeys, NINETEEN_EIGHTY_FOUR, - 'overlaid' + position ) const result = convertLineSpec( STATIC_LEGEND_DEFAULTS, lineSpec, getColumnFormatter, - yColKey + yColKey, + position ) expect(result.length).toEqual(fillColumnKeys.length + 1) result.forEach(legendColumn => { expect( - [...fillColumnKeys, '_value'].indexOf(legendColumn.key) + [...fillColumnKeys, yColKey].indexOf(legendColumn.key) + ).toBeGreaterThanOrEqual(0) + expect(legendColumn.values.length).toEqual( + numberOfRecords / recordsPerLine + ) + }) + }) + + it('creates certain columns for stacked line graphs', () => { + const position = 'stacked' + const addtionalColumKeys = ['cumulative', 'lines'] + const lineSpec = lineTransform( + sampleTable, + xColKey, + yColKey, + fillColumnKeys, + NINETEEN_EIGHTY_FOUR, + position + ) + + const result = convertLineSpec( + STATIC_LEGEND_DEFAULTS, + lineSpec, + getColumnFormatter, + yColKey, + position + ) + + expect(result.length).toEqual(fillColumnKeys.length + 3) + result.forEach(legendColumn => { + expect( + [...fillColumnKeys, ...addtionalColumKeys, `Latest ${yColKey}`].indexOf( + legendColumn.name + ) ).toBeGreaterThanOrEqual(0) expect(legendColumn.values.length).toEqual( numberOfRecords / recordsPerLine diff --git a/giraffe/src/utils/legend/staticLegend.ts b/giraffe/src/utils/legend/staticLegend.ts index 29e1ae2d..76f6f6c1 100644 --- a/giraffe/src/utils/legend/staticLegend.ts +++ b/giraffe/src/utils/legend/staticLegend.ts @@ -1,35 +1,46 @@ import { + DomainLabel, Formatter, LegendData, - LineLayerSpec, LineData, + LineLayerSpec, + LinePosition, StaticLegend, } from '../../types' +import { + FILL, + LINE_COUNT, + STACKED_LINE_CUMULATIVE, +} from '../../constants/columnKeys' -const peek = (arr: number[]): number => { - if (Array.isArray(arr) && arr.length >= 1) { - return arr[arr.length - 1] - } - return NaN -} +import {getDataSortOrder} from './sort' export const convertLineSpec = ( staticLegend: StaticLegend, spec: LineLayerSpec, getColumnFormatter: (colKey: string) => Formatter, - valueColumnKey: string + valueColumnKey: string, + position: LinePosition ): LegendData => { const {valueAxis} = staticLegend const valueFormatter = getColumnFormatter(valueColumnKey) const mappings = spec?.columnGroupMaps?.fill?.mappings + const latestValueIndices = spec?.columnGroupMaps?.latestIndices + const lineValues = spec.table.getColumn(valueColumnKey) + const fillIndices = spec.table.getColumn(FILL) const lineData: LineData = spec?.lineData - const colors = Object.values(lineData).map(line => line.fill) - - const propertyName = valueAxis === 'x' ? 'xs' : 'ys' + const domainLabel = valueAxis === 'x' ? DomainLabel.X : DomainLabel.Y + const sortOrder = getDataSortOrder( + lineData, + Object.values(latestValueIndices), + position, + domainLabel + ) - const values = Object.values(lineData).map(line => { - const latestValue = peek(line[propertyName]) + const colors = sortOrder.map(index => lineData[`${fillIndices[index]}`].fill) + const values = sortOrder.map(index => { + const latestValue = lineValues[index] if (latestValue === latestValue) { return valueFormatter(latestValue) } @@ -49,9 +60,42 @@ export const convertLineSpec = ( values, } - const legendColumns = columnKeys.map(key => { - // TODO: should be using formatter from config - const column: string[] = mappings.map(fillColumn => fillColumn[key]) + const additionalColumns = [] + if (position === 'stacked') { + const stackedDomainValues = spec.stackedDomainValueColumn ?? [] + additionalColumns.push({ + key: valueColumnKey, + name: STACKED_LINE_CUMULATIVE, + type: spec.table.getColumnType(valueColumnKey), + colors, + values: sortOrder.map(index => + valueFormatter(stackedDomainValues[index]) + ), + }) + + const lineCountByGroupId = {} + sortOrder + .map(index => fillIndices[index]) + .sort() + .forEach((groupId, key) => { + lineCountByGroupId[`${groupId}`] = key + 1 + }) + additionalColumns.push({ + key: valueColumnKey, + name: LINE_COUNT, + type: spec.table.getColumnType(valueColumnKey), + colors, + values: sortOrder.map( + index => lineCountByGroupId[`${fillIndices[index]}`] + ), + }) + } + + const fillColumns = columnKeys.map(key => { + const column: string[] = mappings.map(fillColumn => { + const fillFormatter = getColumnFormatter(key) + return fillFormatter(fillColumn[key]) + }) return { key, @@ -62,5 +106,5 @@ export const convertLineSpec = ( } }) - return [valueColumn, ...legendColumns] + return [valueColumn, ...additionalColumns, ...fillColumns] } diff --git a/giraffe/src/utils/legend/tooltip.test.ts b/giraffe/src/utils/legend/tooltip.test.ts index 921173fd..edcba7dd 100644 --- a/giraffe/src/utils/legend/tooltip.test.ts +++ b/giraffe/src/utils/legend/tooltip.test.ts @@ -12,7 +12,7 @@ import { COLUMN_KEY, POINT_KEY, HOST_KEY, -} from '../fixtures/legend' +} from '../fixtures/randomTable' import {LayerTypes, LineLayerSpec, ScatterLayerSpec} from '../../types' describe('getPointsTooltipData', () => { diff --git a/giraffe/src/utils/legend/tooltip.ts b/giraffe/src/utils/legend/tooltip.ts index 5f0f5f99..9fc9c5b0 100644 --- a/giraffe/src/utils/legend/tooltip.ts +++ b/giraffe/src/utils/legend/tooltip.ts @@ -1,5 +1,4 @@ import { - DomainLabel, LineData, LinePosition, NumericColumnData, @@ -17,6 +16,7 @@ import { } from '../../constants/columnKeys' import {BandHoverIndices} from '../bandHover' +import {getDataSortOrder} from './sort' const isVoid = (x: any) => x === null || x === undefined @@ -30,32 +30,6 @@ const orderDataByValue = ( return nextOrder.map(place => dataMap[place]) } -const getDataSortOrder = ( - lineData: LineData, - hoveredRowIndices: number[], - position: LinePosition -): number[] => { - if (!position || position === 'overlaid') { - return hoveredRowIndices - } - - const dataMap = {} - const measurementValues = Object.keys(lineData).reduce( - (accumulator, id) => accumulator.concat(lineData[id][DomainLabel.Y]), - [] - ) - const sortable = [] - hoveredRowIndices.forEach(hoveredRowIndex => { - if (!dataMap[measurementValues[hoveredRowIndex]]) { - dataMap[measurementValues[hoveredRowIndex]] = [] - } - dataMap[measurementValues[hoveredRowIndex]].push(hoveredRowIndex) - sortable.push(measurementValues[hoveredRowIndex]) - }) - sortable.sort((first, second) => second - first) - return sortable.map(measurement => dataMap[measurement].shift()) -} - export const getRangeLabel = (min: number, max: number, formatter): string => { let label = '' @@ -109,6 +83,7 @@ export const getPointsTooltipData = ( const sortOrder = lineData ? getDataSortOrder(lineData, hoveredRowIndices, position) : hoveredRowIndices + const xColData = table.getColumn(xColKey, 'number') const yColData = table.getColumn(yColKey, 'number') const groupColData = table.getColumn(groupColKey, 'number') diff --git a/stories/src/linegraph.stories.tsx b/stories/src/linegraph.stories.tsx index b1282fb5..f6bdbc73 100644 --- a/stories/src/linegraph.stories.tsx +++ b/stories/src/linegraph.stories.tsx @@ -3,7 +3,7 @@ import {storiesOf} from '@storybook/react' import {withKnobs, number, select, boolean, text} from '@storybook/addon-knobs' import {Config, Plot, timeFormatter, fromFlux} from '../../giraffe/src' -import {getRandomTable} from './data/randomTable' +import {getRandomTable} from '../../giraffe/src/utils/fixtures/randomTable' import { PlotContainer, @@ -30,7 +30,7 @@ const maxValue = Math.random() * Math.floor(200) storiesOf('Line Graph', module) .addDecorator(withKnobs) .add('User defined ticks', () => { - let table = getRandomTable(maxValue) + let table = getRandomTable(maxValue, false) const xTickStart = number('xTickStart', new Date().getTime()) const xTickStep = number('xTickStep', 200_000) const xTotalTicks = number('xTotalTicks', 5) diff --git a/stories/src/staticLegend.stories.tsx b/stories/src/staticLegend.stories.tsx index 52a7477c..254df021 100644 --- a/stories/src/staticLegend.stories.tsx +++ b/stories/src/staticLegend.stories.tsx @@ -3,7 +3,7 @@ import {storiesOf} from '@storybook/react' import {withKnobs, number, select, boolean, text} from '@storybook/addon-knobs' import {Config, Plot, timeFormatter} from '../../giraffe/src' -import {getRandomTable} from './data/randomTable' +import {getRandomTable} from '../../giraffe/src/utils/fixtures/randomTable' import { PlotContainer, @@ -48,8 +48,15 @@ storiesOf('Static Legend', module) fixedPlotSize['height'] = fixedHeight fixedPlotSize['width'] = fixedWidth } + const includeNegativeNumbers = boolean('Include negative numbers ?', false) + const position = select( + 'Line Position', + {stacked: 'stacked', overlaid: 'overlaid'}, + 'overlaid' + ) const table = getRandomTable( maxValue, + includeNegativeNumbers, lines * 20, 20, fillColumnsCount, @@ -98,11 +105,6 @@ storiesOf('Static Legend', module) 'YYYY-MM-DD HH:mm:ss ZZ' ) const fill = fillKnob(table, findStringColumns(table)) - const position = select( - 'Line Position', - {stacked: 'stacked', overlaid: 'overlaid'}, - 'overlaid' - ) const interpolation = interpolationKnob() const showAxes = showAxesKnob() const lineWidth = number('Line Width', 1) @@ -191,7 +193,19 @@ storiesOf('Static Legend', module) fixedPlotSize['height'] = fixedHeight fixedPlotSize['width'] = fixedWidth } - const table = getRandomTable(maxValue, 20 * lines, 20, fillColumnNames) + const includeNegativeNumbers = boolean('Include negative numbers ?', false) + const position = select( + 'Line Position', + {stacked: 'stacked', overlaid: 'overlaid'}, + 'overlaid' + ) + const table = getRandomTable( + maxValue, + includeNegativeNumbers, + 20 * lines, + 20, + fillColumnNames + ) const colors = colorSchemeKnob() const legendOrientationThreshold = tooltipOrientationThresholdKnob(20) const staticLegendOrientationThreshold = number( @@ -235,11 +249,6 @@ storiesOf('Static Legend', module) 'YYYY-MM-DD HH:mm:ss ZZ' ) const fill = fillKnob(table, findStringColumns(table)) - const position = select( - 'Line Position', - {stacked: 'stacked', overlaid: 'overlaid'}, - 'overlaid' - ) const interpolation = interpolationKnob() const showAxes = showAxesKnob() const lineWidth = number('Line Width', 1)