From 9d7b1595891d87d6853e37355b63845f796f179d Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Tue, 26 Mar 2019 22:59:16 +0100 Subject: [PATCH] fix(rendering): fix rendering values <= 0 on log scale (#114) Instead of throwing errors or warnings, if the user is using a log scale with a dataset with 0 values, we will hide them on the rendering of line and area charts. This fix also the defined area of the chart fix #112, fix #63 --- src/lib/series/rendering.areas.test.ts | 764 ++++++++++++ src/lib/series/rendering.bars.test.ts | 10 +- ...points.test.ts => rendering.lines.test.ts} | 83 +- src/lib/series/rendering.ts | 89 +- src/lib/series/utils/test_dataset_tsvb.ts | 1055 +++++++++++++++++ src/lib/utils/scales/scale_continuous.test.ts | 17 +- src/lib/utils/scales/scale_continuous.ts | 4 + stories/line_chart.tsx | 35 + 8 files changed, 2015 insertions(+), 42 deletions(-) create mode 100644 src/lib/series/rendering.areas.test.ts rename src/lib/series/{rendering.points.test.ts => rendering.lines.test.ts} (86%) create mode 100644 src/lib/series/utils/test_dataset_tsvb.ts diff --git a/src/lib/series/rendering.areas.test.ts b/src/lib/series/rendering.areas.test.ts new file mode 100644 index 0000000000..377eab8439 --- /dev/null +++ b/src/lib/series/rendering.areas.test.ts @@ -0,0 +1,764 @@ +import { computeSeriesDomains } from '../../state/utils'; +import { getGroupId, getSpecId } from '../utils/ids'; +import { ScaleType } from '../utils/scales/scales'; +import { CurveType } from './curves'; +import { AreaGeometry, IndexedGeometry, renderArea } from './rendering'; +import { computeXScale, computeYScales } from './scales'; +import { AreaSeriesSpec } from './specs'; +const SPEC_ID = getSpecId('spec_1'); +const GROUP_ID = getGroupId('group_1'); + +describe('Rendering points - areas', () => { + describe('Single series area chart - ordinal', () => { + const pointSeriesSpec: AreaSeriesSpec = { + id: SPEC_ID, + groupId: GROUP_ID, + seriesType: 'area', + yScaleToDataExtent: false, + data: [[0, 10], [1, 5]], + xAccessor: 0, + yAccessors: [1], + xScaleType: ScaleType.Ordinal, + yScaleType: ScaleType.Linear, + }; + const pointSeriesMap = new Map(); + pointSeriesMap.set(SPEC_ID, pointSeriesSpec); + const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); + const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + let renderedArea: { + areaGeometry: AreaGeometry; + indexedGeometries: Map; + }; + + beforeEach(() => { + renderedArea = renderArea( + 25, // adding a ideal 25px shift, generally applied by renderGeometries + pointSeriesDomains.formattedDataSeries.nonStacked[0].dataSeries[0].data, + xScale, + yScales.get(GROUP_ID)!, + 'red', + CurveType.LINEAR, + SPEC_ID, + [], + ); + }); + test('Can render an line and area paths', () => { + const { + areaGeometry: { line, area, color, geometryId, transform }, + } = renderedArea; + expect(line).toBe('M0,0L50,50'); + expect(area).toBe('M0,0L50,50L50,100L0,100Z'); + expect(color).toBe('red'); + expect(geometryId.seriesKey).toEqual([]); + expect(geometryId.specId).toEqual(SPEC_ID); + expect(transform).toEqual({ x: 25, y: 0 }); + }); + + test('Can render two points', () => { + const { + areaGeometry: { points }, + indexedGeometries, + } = renderedArea; + + expect(points[0]).toEqual({ + x: 0, + y: 0, + color: 'red', + value: { + specId: SPEC_ID, + seriesKey: [], + datum: [0, 10], + }, + transform: { + x: 25, + y: 0, + }, + }); + expect(points[1]).toEqual({ + x: 50, + y: 50, + color: 'red', + value: { + specId: SPEC_ID, + seriesKey: [], + datum: [1, 5], + }, + transform: { + x: 25, + y: 0, + }, + }); + expect(indexedGeometries.size).toEqual(points.length); + }); + }); + describe('Multi series area chart - ordinal', () => { + const spec1Id = getSpecId('point1'); + const spec2Id = getSpecId('point2'); + const pointSeriesSpec1: AreaSeriesSpec = { + id: spec1Id, + groupId: GROUP_ID, + seriesType: 'area', + yScaleToDataExtent: false, + data: [[0, 10], [1, 5]], + xAccessor: 0, + yAccessors: [1], + xScaleType: ScaleType.Ordinal, + yScaleType: ScaleType.Linear, + }; + const pointSeriesSpec2: AreaSeriesSpec = { + id: spec2Id, + groupId: GROUP_ID, + seriesType: 'area', + yScaleToDataExtent: false, + data: [[0, 20], [1, 10]], + xAccessor: 0, + yAccessors: [1], + xScaleType: ScaleType.Ordinal, + yScaleType: ScaleType.Linear, + }; + const pointSeriesMap = new Map(); + pointSeriesMap.set(spec1Id, pointSeriesSpec1); + pointSeriesMap.set(spec2Id, pointSeriesSpec2); + const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); + const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + + let firstLine: { + areaGeometry: AreaGeometry; + indexedGeometries: Map; + }; + let secondLine: { + areaGeometry: AreaGeometry; + indexedGeometries: Map; + }; + + beforeEach(() => { + firstLine = renderArea( + 25, // adding a ideal 25px shift, generally applied by renderGeometries + pointSeriesDomains.formattedDataSeries.nonStacked[0].dataSeries[0].data, + xScale, + yScales.get(GROUP_ID)!, + 'red', + CurveType.LINEAR, + spec1Id, + [], + ); + secondLine = renderArea( + 25, // adding a ideal 25px shift, generally applied by renderGeometries + pointSeriesDomains.formattedDataSeries.nonStacked[0].dataSeries[1].data, + xScale, + yScales.get(GROUP_ID)!, + 'blue', + CurveType.LINEAR, + spec2Id, + [], + ); + }); + + test('Can render two ordinal areas', () => { + expect(firstLine.areaGeometry.line).toBe('M0,50L50,75'); + expect(firstLine.areaGeometry.area).toBe('M0,50L50,75L50,100L0,100Z'); + expect(firstLine.areaGeometry.color).toBe('red'); + expect(firstLine.areaGeometry.geometryId.seriesKey).toEqual([]); + expect(firstLine.areaGeometry.geometryId.specId).toEqual(spec1Id); + expect(firstLine.areaGeometry.transform).toEqual({ x: 25, y: 0 }); + + expect(secondLine.areaGeometry.line).toBe('M0,0L50,50'); + expect(secondLine.areaGeometry.area).toBe('M0,0L50,50L50,100L0,100Z'); + expect(secondLine.areaGeometry.color).toBe('blue'); + expect(secondLine.areaGeometry.geometryId.seriesKey).toEqual([]); + expect(secondLine.areaGeometry.geometryId.specId).toEqual(spec2Id); + expect(secondLine.areaGeometry.transform).toEqual({ x: 25, y: 0 }); + }); + test('can render first spec points', () => { + const { + areaGeometry: { points }, + indexedGeometries, + } = firstLine; + expect(points.length).toEqual(2); + expect(points[0]).toEqual({ + x: 0, + y: 50, + color: 'red', + value: { + specId: spec1Id, + seriesKey: [], + datum: [0, 10], + }, + transform: { + x: 25, + y: 0, + }, + }); + expect(points[1]).toEqual({ + x: 50, + y: 75, + color: 'red', + value: { + specId: spec1Id, + seriesKey: [], + datum: [1, 5], + }, + transform: { + x: 25, + y: 0, + }, + }); + expect(indexedGeometries.size).toEqual(points.length); + }); + test('can render second spec points', () => { + const { + areaGeometry: { points }, + indexedGeometries, + } = secondLine; + expect(points.length).toEqual(2); + expect(points[0]).toEqual({ + x: 0, + y: 0, + color: 'blue', + value: { + specId: spec2Id, + seriesKey: [], + datum: [0, 20], + }, + transform: { + x: 25, + y: 0, + }, + }); + expect(points[1]).toEqual({ + x: 50, + y: 50, + color: 'blue', + value: { + specId: spec2Id, + seriesKey: [], + datum: [1, 10], + }, + transform: { + x: 25, + y: 0, + }, + }); + expect(indexedGeometries.size).toEqual(points.length); + }); + }); + describe('Single series area chart - linear', () => { + const pointSeriesSpec: AreaSeriesSpec = { + id: SPEC_ID, + groupId: GROUP_ID, + seriesType: 'area', + yScaleToDataExtent: false, + data: [[0, 10], [1, 5]], + xAccessor: 0, + yAccessors: [1], + xScaleType: ScaleType.Linear, + yScaleType: ScaleType.Linear, + }; + const pointSeriesMap = new Map(); + pointSeriesMap.set(SPEC_ID, pointSeriesSpec); + const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); + const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + + let renderedArea: { + areaGeometry: AreaGeometry; + indexedGeometries: Map; + }; + + beforeEach(() => { + renderedArea = renderArea( + 0, // not applied any shift, renderGeometries applies it only with mixed charts + pointSeriesDomains.formattedDataSeries.nonStacked[0].dataSeries[0].data, + xScale, + yScales.get(GROUP_ID)!, + 'red', + CurveType.LINEAR, + SPEC_ID, + [], + ); + }); + test('Can render a linear area', () => { + expect(renderedArea.areaGeometry.line).toBe('M0,0L100,50'); + expect(renderedArea.areaGeometry.area).toBe('M0,0L100,50L100,100L0,100Z'); + expect(renderedArea.areaGeometry.color).toBe('red'); + expect(renderedArea.areaGeometry.geometryId.seriesKey).toEqual([]); + expect(renderedArea.areaGeometry.geometryId.specId).toEqual(SPEC_ID); + expect(renderedArea.areaGeometry.transform).toEqual({ x: 0, y: 0 }); + }); + test('Can render two points', () => { + const { + areaGeometry: { points }, + indexedGeometries, + } = renderedArea; + expect(points[0]).toEqual({ + x: 0, + y: 0, + color: 'red', + value: { + specId: SPEC_ID, + seriesKey: [], + datum: [0, 10], + }, + transform: { + x: 0, + y: 0, + }, + }); + expect(points[1]).toEqual({ + x: 100, + y: 50, + color: 'red', + value: { + specId: SPEC_ID, + seriesKey: [], + datum: [1, 5], + }, + transform: { + x: 0, + y: 0, + }, + }); + expect(indexedGeometries.size).toEqual(points.length); + }); + }); + describe('Multi series area chart - linear', () => { + const spec1Id = getSpecId('point1'); + const spec2Id = getSpecId('point2'); + const pointSeriesSpec1: AreaSeriesSpec = { + id: spec1Id, + groupId: GROUP_ID, + seriesType: 'area', + yScaleToDataExtent: false, + data: [[0, 10], [1, 5]], + xAccessor: 0, + yAccessors: [1], + xScaleType: ScaleType.Linear, + yScaleType: ScaleType.Linear, + }; + const pointSeriesSpec2: AreaSeriesSpec = { + id: spec2Id, + groupId: GROUP_ID, + seriesType: 'area', + yScaleToDataExtent: false, + data: [[0, 20], [1, 10]], + xAccessor: 0, + yAccessors: [1], + xScaleType: ScaleType.Linear, + yScaleType: ScaleType.Linear, + }; + const pointSeriesMap = new Map(); + pointSeriesMap.set(spec1Id, pointSeriesSpec1); + pointSeriesMap.set(spec2Id, pointSeriesSpec2); + const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); + const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + + let firstLine: { + areaGeometry: AreaGeometry; + indexedGeometries: Map; + }; + let secondLine: { + areaGeometry: AreaGeometry; + indexedGeometries: Map; + }; + + beforeEach(() => { + firstLine = renderArea( + 0, // not applied any shift, renderGeometries applies it only with mixed charts + pointSeriesDomains.formattedDataSeries.nonStacked[0].dataSeries[0].data, + xScale, + yScales.get(GROUP_ID)!, + 'red', + CurveType.LINEAR, + spec1Id, + [], + ); + secondLine = renderArea( + 0, // not applied any shift, renderGeometries applies it only with mixed charts + pointSeriesDomains.formattedDataSeries.nonStacked[0].dataSeries[1].data, + xScale, + yScales.get(GROUP_ID)!, + 'blue', + CurveType.LINEAR, + spec2Id, + [], + ); + }); + test('can render two linear areas', () => { + expect(firstLine.areaGeometry.line).toBe('M0,50L100,75'); + expect(firstLine.areaGeometry.area).toBe('M0,50L100,75L100,100L0,100Z'); + expect(firstLine.areaGeometry.color).toBe('red'); + expect(firstLine.areaGeometry.geometryId.seriesKey).toEqual([]); + expect(firstLine.areaGeometry.geometryId.specId).toEqual(spec1Id); + expect(firstLine.areaGeometry.transform).toEqual({ x: 0, y: 0 }); + + expect(secondLine.areaGeometry.line).toBe('M0,0L100,50'); + expect(secondLine.areaGeometry.area).toBe('M0,0L100,50L100,100L0,100Z'); + expect(secondLine.areaGeometry.color).toBe('blue'); + expect(secondLine.areaGeometry.geometryId.seriesKey).toEqual([]); + expect(secondLine.areaGeometry.geometryId.specId).toEqual(spec2Id); + expect(secondLine.areaGeometry.transform).toEqual({ x: 0, y: 0 }); + }); + test('can render first spec points', () => { + const { + areaGeometry: { points }, + indexedGeometries, + } = firstLine; + expect(points.length).toEqual(2); + expect(points[0]).toEqual({ + x: 0, + y: 50, + color: 'red', + value: { + specId: spec1Id, + seriesKey: [], + datum: [0, 10], + }, + transform: { + x: 0, + y: 0, + }, + }); + expect(points[1]).toEqual({ + x: 100, + y: 75, + color: 'red', + value: { + specId: spec1Id, + seriesKey: [], + datum: [1, 5], + }, + transform: { + x: 0, + y: 0, + }, + }); + expect(indexedGeometries.size).toEqual(points.length); + }); + test('can render second spec points', () => { + const { + areaGeometry: { points }, + indexedGeometries, + } = secondLine; + expect(points.length).toEqual(2); + expect(points[0]).toEqual({ + x: 0, + y: 0, + color: 'blue', + value: { + specId: spec2Id, + seriesKey: [], + datum: [0, 20], + }, + transform: { + x: 0, + y: 0, + }, + }); + expect(points[1]).toEqual({ + x: 100, + y: 50, + color: 'blue', + value: { + specId: spec2Id, + seriesKey: [], + datum: [1, 10], + }, + transform: { + x: 0, + y: 0, + }, + }); + expect(indexedGeometries.size).toEqual(points.length); + }); + }); + describe('Single series area chart - time', () => { + const pointSeriesSpec: AreaSeriesSpec = { + id: SPEC_ID, + groupId: GROUP_ID, + seriesType: 'area', + yScaleToDataExtent: false, + data: [[1546300800000, 10], [1546387200000, 5]], + xAccessor: 0, + yAccessors: [1], + xScaleType: ScaleType.Time, + yScaleType: ScaleType.Linear, + }; + const pointSeriesMap = new Map(); + pointSeriesMap.set(SPEC_ID, pointSeriesSpec); + const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); + const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + + let renderedArea: { + areaGeometry: AreaGeometry; + indexedGeometries: Map; + }; + + beforeEach(() => { + renderedArea = renderArea( + 0, // not applied any shift, renderGeometries applies it only with mixed charts + pointSeriesDomains.formattedDataSeries.nonStacked[0].dataSeries[0].data, + xScale, + yScales.get(GROUP_ID)!, + 'red', + CurveType.LINEAR, + SPEC_ID, + [], + ); + }); + test('Can render a time area', () => { + expect(renderedArea.areaGeometry.line).toBe('M0,0L100,50'); + expect(renderedArea.areaGeometry.area).toBe('M0,0L100,50L100,100L0,100Z'); + expect(renderedArea.areaGeometry.color).toBe('red'); + expect(renderedArea.areaGeometry.geometryId.seriesKey).toEqual([]); + expect(renderedArea.areaGeometry.geometryId.specId).toEqual(SPEC_ID); + expect(renderedArea.areaGeometry.transform).toEqual({ x: 0, y: 0 }); + }); + test('Can render two points', () => { + const { + areaGeometry: { points }, + indexedGeometries, + } = renderedArea; + expect(points[0]).toEqual({ + x: 0, + y: 0, + color: 'red', + value: { + specId: SPEC_ID, + seriesKey: [], + datum: [1546300800000, 10], + }, + transform: { + x: 0, + y: 0, + }, + }); + expect(points[1]).toEqual({ + x: 100, + y: 50, + color: 'red', + value: { + specId: SPEC_ID, + seriesKey: [], + datum: [1546387200000, 5], + }, + transform: { + x: 0, + y: 0, + }, + }); + expect(indexedGeometries.size).toEqual(points.length); + }); + }); + describe('Multi series area chart - time', () => { + const spec1Id = getSpecId('point1'); + const spec2Id = getSpecId('point2'); + const pointSeriesSpec1: AreaSeriesSpec = { + id: spec1Id, + groupId: GROUP_ID, + seriesType: 'area', + yScaleToDataExtent: false, + data: [[1546300800000, 10], [1546387200000, 5]], + xAccessor: 0, + yAccessors: [1], + xScaleType: ScaleType.Time, + yScaleType: ScaleType.Linear, + }; + const pointSeriesSpec2: AreaSeriesSpec = { + id: spec2Id, + groupId: GROUP_ID, + seriesType: 'area', + yScaleToDataExtent: false, + data: [[1546300800000, 20], [1546387200000, 10]], + xAccessor: 0, + yAccessors: [1], + xScaleType: ScaleType.Time, + yScaleType: ScaleType.Linear, + }; + const pointSeriesMap = new Map(); + pointSeriesMap.set(spec1Id, pointSeriesSpec1); + pointSeriesMap.set(spec2Id, pointSeriesSpec2); + const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); + const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 100); + const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + + let firstLine: { + areaGeometry: AreaGeometry; + indexedGeometries: Map; + }; + let secondLine: { + areaGeometry: AreaGeometry; + indexedGeometries: Map; + }; + + beforeEach(() => { + firstLine = renderArea( + 0, // not applied any shift, renderGeometries applies it only with mixed charts + pointSeriesDomains.formattedDataSeries.nonStacked[0].dataSeries[0].data, + xScale, + yScales.get(GROUP_ID)!, + 'red', + CurveType.LINEAR, + spec1Id, + [], + ); + secondLine = renderArea( + 0, // not applied any shift, renderGeometries applies it only with mixed charts + pointSeriesDomains.formattedDataSeries.nonStacked[0].dataSeries[1].data, + xScale, + yScales.get(GROUP_ID)!, + 'blue', + CurveType.LINEAR, + spec2Id, + [], + ); + }); + test('can render first spec points', () => { + const { + areaGeometry: { points }, + indexedGeometries, + } = firstLine; + expect(points.length).toEqual(2); + expect(points[0]).toEqual({ + x: 0, + y: 50, + color: 'red', + value: { + specId: spec1Id, + seriesKey: [], + datum: [1546300800000, 10], + }, + transform: { + x: 0, + y: 0, + }, + }); + expect(points[1]).toEqual({ + x: 100, + y: 75, + color: 'red', + value: { + specId: spec1Id, + seriesKey: [], + datum: [1546387200000, 5], + }, + transform: { + x: 0, + y: 0, + }, + }); + expect(indexedGeometries.size).toEqual(points.length); + }); + test('can render second spec points', () => { + const { + areaGeometry: { points }, + indexedGeometries, + } = secondLine; + expect(points.length).toEqual(2); + expect(points[0]).toEqual({ + x: 0, + y: 0, + color: 'blue', + value: { + specId: spec2Id, + seriesKey: [], + datum: [1546300800000, 20], + }, + transform: { + x: 0, + y: 0, + }, + }); + expect(points[1]).toEqual({ + x: 100, + y: 50, + color: 'blue', + value: { + specId: spec2Id, + seriesKey: [], + datum: [1546387200000, 10], + }, + transform: { + x: 0, + y: 0, + }, + }); + expect(indexedGeometries.size).toEqual(points.length); + }); + }); + describe('Single series area chart - y log', () => { + const pointSeriesSpec: AreaSeriesSpec = { + id: SPEC_ID, + groupId: GROUP_ID, + seriesType: 'area', + yScaleToDataExtent: false, + data: [[0, 10], [1, 5], [2, null], [3, 5], [4, 5], [5, 0], [6, 10], [7, 10], [8, 10]], + xAccessor: 0, + yAccessors: [1], + xScaleType: ScaleType.Linear, + yScaleType: ScaleType.Log, + }; + const pointSeriesMap = new Map(); + pointSeriesMap.set(SPEC_ID, pointSeriesSpec); + const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); + const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 90); + const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + + let renderedArea: { + areaGeometry: AreaGeometry; + indexedGeometries: Map; + }; + + beforeEach(() => { + renderedArea = renderArea( + 0, // not applied any shift, renderGeometries applies it only with mixed charts + pointSeriesDomains.formattedDataSeries.nonStacked[0].dataSeries[0].data, + xScale, + yScales.get(GROUP_ID)!, + 'red', + CurveType.LINEAR, + SPEC_ID, + [], + ); + }); + test('Can render a splitted area and line', () => { + // expect(renderedArea.lineGeometry.line).toBe('ss'); + expect(renderedArea.areaGeometry.line.split('M').length - 1).toBe(3); + expect(renderedArea.areaGeometry.area.split('M').length - 1).toBe(3); + expect(renderedArea.areaGeometry.color).toBe('red'); + expect(renderedArea.areaGeometry.geometryId.seriesKey).toEqual([]); + expect(renderedArea.areaGeometry.geometryId.specId).toEqual(SPEC_ID); + expect(renderedArea.areaGeometry.transform).toEqual({ x: 0, y: 0 }); + }); + test('Can render points points', () => { + const { + areaGeometry: { points }, + indexedGeometries, + } = renderedArea; + // all the points minus the undefined ones on a log scale + expect(points.length).toBe(7); + // all the points + expect(indexedGeometries.size).toEqual(9); + const nullIndexdGeometry = indexedGeometries.get(2); + expect(nullIndexdGeometry).toBeDefined(); + expect(nullIndexdGeometry!.length).toBe(1); + // moved to the bottom of the chart + expect(nullIndexdGeometry![0].geom.y).toBe(100); + // 0 radius point + expect(nullIndexdGeometry![0].geom.width).toBe(0); + expect(nullIndexdGeometry![0].geom.height).toBe(0); + + const zeroValueIndexdGeometry = indexedGeometries.get(5); + expect(zeroValueIndexdGeometry).toBeDefined(); + expect(zeroValueIndexdGeometry!.length).toBe(1); + // moved to the bottom of the chart + expect(zeroValueIndexdGeometry![0].geom.y).toBe(100); + // 0 radius point + expect(zeroValueIndexdGeometry![0].geom.width).toBe(0); + expect(zeroValueIndexdGeometry![0].geom.height).toBe(0); + }); + }); +}); diff --git a/src/lib/series/rendering.bars.test.ts b/src/lib/series/rendering.bars.test.ts index 6be36c1729..cc1013f5ec 100644 --- a/src/lib/series/rendering.bars.test.ts +++ b/src/lib/series/rendering.bars.test.ts @@ -8,7 +8,7 @@ const SPEC_ID = getSpecId('spec_1'); const GROUP_ID = getGroupId('group_1'); describe('Rendering bars', () => { - describe('Single series barchart - ordinal', () => { + describe('Single series bar chart - ordinal', () => { const barSeriesSpec: BarSeriesSpec = { id: SPEC_ID, groupId: GROUP_ID, @@ -70,7 +70,7 @@ describe('Rendering bars', () => { }); }); }); - describe('Multi series barchart - ordinal', () => { + describe('Multi series bar chart - ordinal', () => { const spec1Id = getSpecId('bar1'); const spec2Id = getSpecId('bar2'); const barSeriesSpec1: BarSeriesSpec = { @@ -191,7 +191,7 @@ describe('Rendering bars', () => { }); }); }); - describe('Single series barchart - lineaar', () => { + describe('Single series bar chart - lineaar', () => { const barSeriesSpec: BarSeriesSpec = { id: SPEC_ID, groupId: GROUP_ID, @@ -253,7 +253,7 @@ describe('Rendering bars', () => { }); }); }); - describe('Multi series barchart - linear', () => { + describe('Multi series bar chart - linear', () => { const spec1Id = getSpecId('bar1'); const spec2Id = getSpecId('bar2'); const barSeriesSpec1: BarSeriesSpec = { @@ -374,7 +374,7 @@ describe('Rendering bars', () => { }); }); }); - describe('Multi series barchart - time', () => { + describe('Multi series bar chart - time', () => { const spec1Id = getSpecId('bar1'); const spec2Id = getSpecId('bar2'); const barSeriesSpec1: BarSeriesSpec = { diff --git a/src/lib/series/rendering.points.test.ts b/src/lib/series/rendering.lines.test.ts similarity index 86% rename from src/lib/series/rendering.points.test.ts rename to src/lib/series/rendering.lines.test.ts index 34fbdc61cc..717d089b77 100644 --- a/src/lib/series/rendering.points.test.ts +++ b/src/lib/series/rendering.lines.test.ts @@ -9,7 +9,7 @@ const SPEC_ID = getSpecId('spec_1'); const GROUP_ID = getGroupId('group_1'); describe('Rendering points - line', () => { - describe('Single series point chart - ordinal', () => { + describe('Single series line chart - ordinal', () => { const pointSeriesSpec: LineSeriesSpec = { id: SPEC_ID, groupId: GROUP_ID, @@ -88,7 +88,7 @@ describe('Rendering points - line', () => { expect(indexedGeometries.size).toEqual(points.length); }); }); - describe('Multi series pointchart - ordinal', () => { + describe('Multi series line chart - ordinal', () => { const spec1Id = getSpecId('point1'); const spec2Id = getSpecId('point2'); const pointSeriesSpec1: LineSeriesSpec = { @@ -238,7 +238,7 @@ describe('Rendering points - line', () => { expect(indexedGeometries.size).toEqual(points.length); }); }); - describe('Single series pointchart - linear', () => { + describe('Single series line chart - linear', () => { const pointSeriesSpec: LineSeriesSpec = { id: SPEC_ID, groupId: GROUP_ID, @@ -316,7 +316,7 @@ describe('Rendering points - line', () => { expect(indexedGeometries.size).toEqual(points.length); }); }); - describe('Multi series pointchart - linear', () => { + describe('Multi series line chart - linear', () => { const spec1Id = getSpecId('point1'); const spec2Id = getSpecId('point2'); const pointSeriesSpec1: LineSeriesSpec = { @@ -465,7 +465,7 @@ describe('Rendering points - line', () => { expect(indexedGeometries.size).toEqual(points.length); }); }); - describe('Single series pointchart - time', () => { + describe('Single series line chart - time', () => { const pointSeriesSpec: LineSeriesSpec = { id: SPEC_ID, groupId: GROUP_ID, @@ -543,7 +543,7 @@ describe('Rendering points - line', () => { expect(indexedGeometries.size).toEqual(points.length); }); }); - describe('Multi series pointchart - time', () => { + describe('Multi series line chart - time', () => { const spec1Id = getSpecId('point1'); const spec2Id = getSpecId('point2'); const pointSeriesSpec1: LineSeriesSpec = { @@ -679,4 +679,75 @@ describe('Rendering points - line', () => { expect(indexedGeometries.size).toEqual(points.length); }); }); + describe('Single series line chart - y log', () => { + const pointSeriesSpec: LineSeriesSpec = { + id: SPEC_ID, + groupId: GROUP_ID, + seriesType: 'line', + yScaleToDataExtent: false, + data: [[0, 10], [1, 5], [2, null], [3, 5], [4, 5], [5, 0], [6, 10], [7, 10], [8, 10]], + xAccessor: 0, + yAccessors: [1], + xScaleType: ScaleType.Linear, + yScaleType: ScaleType.Log, + }; + const pointSeriesMap = new Map(); + pointSeriesMap.set(SPEC_ID, pointSeriesSpec); + const pointSeriesDomains = computeSeriesDomains(pointSeriesMap, new Map()); + const xScale = computeXScale(pointSeriesDomains.xDomain, pointSeriesMap.size, 0, 90); + const yScales = computeYScales(pointSeriesDomains.yDomain, 100, 0); + + let renderedLine: { + lineGeometry: LineGeometry; + indexedGeometries: Map; + }; + + beforeEach(() => { + renderedLine = renderLine( + 0, // not applied any shift, renderGeometries applies it only with mixed charts + pointSeriesDomains.formattedDataSeries.nonStacked[0].dataSeries[0].data, + xScale, + yScales.get(GROUP_ID)!, + 'red', + CurveType.LINEAR, + SPEC_ID, + [], + ); + }); + test('Can render a splitted line', () => { + // expect(renderedLine.lineGeometry.line).toBe('ss'); + expect(renderedLine.lineGeometry.line.split('M').length - 1).toBe(3); + expect(renderedLine.lineGeometry.color).toBe('red'); + expect(renderedLine.lineGeometry.geometryId.seriesKey).toEqual([]); + expect(renderedLine.lineGeometry.geometryId.specId).toEqual(SPEC_ID); + expect(renderedLine.lineGeometry.transform).toEqual({ x: 0, y: 0 }); + }); + test('Can render points', () => { + const { + lineGeometry: { points }, + indexedGeometries, + } = renderedLine; + // all the points minus the undefined ones on a log scale + expect(points.length).toBe(7); + // all the points + expect(indexedGeometries.size).toEqual(9); + const nullIndexdGeometry = indexedGeometries.get(2); + expect(nullIndexdGeometry).toBeDefined(); + expect(nullIndexdGeometry!.length).toBe(1); + // moved to the bottom of the chart + expect(nullIndexdGeometry![0].geom.y).toBe(100); + // 0 radius point + expect(nullIndexdGeometry![0].geom.width).toBe(0); + expect(nullIndexdGeometry![0].geom.height).toBe(0); + + const zeroValueIndexdGeometry = indexedGeometries.get(5); + expect(zeroValueIndexdGeometry).toBeDefined(); + expect(zeroValueIndexdGeometry!.length).toBe(1); + // moved to the bottom of the chart + expect(zeroValueIndexdGeometry![0].geom.y).toBe(100); + // 0 radius point + expect(zeroValueIndexdGeometry![0].geom.width).toBe(0); + expect(zeroValueIndexdGeometry![0].geom.height).toBe(0); + }); + }); }); diff --git a/src/lib/series/rendering.ts b/src/lib/series/rendering.ts index dcef8e664d..6d3e204293 100644 --- a/src/lib/series/rendering.ts +++ b/src/lib/series/rendering.ts @@ -2,6 +2,7 @@ import { area, line } from 'd3-shape'; import { mutableIndexedGeometryMapUpsert } from '../../state/utils'; import { SharedGeometryStyle } from '../themes/theme'; import { SpecId } from '../utils/ids'; +import { isLogarithmicScale } from '../utils/scales/scale_continuous'; import { Scale, ScaleType } from '../utils/scales/scales'; import { CurveType, getCurveFactory } from './curves'; import { LegendItem } from './legend'; @@ -87,39 +88,56 @@ export function renderPoints( indexedGeometries: Map; } { const indexedGeometries: Map = new Map(); + const isLogScale = isLogarithmicScale(yScale); - const pointGeometries = dataset.map((datum) => { - const x = xScale.scale(datum.x); - const y = yScale.scale(datum.y1); - const indexedGeometry: IndexedGeometry = { - specId, - datum: datum.datum, - color, - seriesKey, - geom: { - x: x + shift, - y, - width: 10, - height: 10, - isPoint: true, - }, - }; - mutableIndexedGeometryMapUpsert(indexedGeometries, datum.x, indexedGeometry); - return { - x, - y, - color, - value: { + const pointGeometries = dataset.reduce( + (acc, datum) => { + const x = xScale.scale(datum.x); + let y; + let radius = 10; + const isHidden = datum.y1 === null || (isLogScale && datum.y1 <= 0); + // we fix 0 and negative values at y = 0 + if (isHidden) { + y = yScale.range[0]; + radius = 0; + } else { + y = yScale.scale(datum.y1); + } + const indexedGeometry: IndexedGeometry = { specId, datum: datum.datum, + color, seriesKey, - }, - transform: { - x: shift, - y: 0, - }, - }; - }); + geom: { + x: x + shift, + y, + width: radius, + height: radius, + isPoint: true, + }, + }; + mutableIndexedGeometryMapUpsert(indexedGeometries, datum.x, indexedGeometry); + const pointGeometry: PointGeometry = { + x, + y, + color, + value: { + specId, + datum: datum.datum, + seriesKey, + }, + transform: { + x: shift, + y: 0, + }, + }; + if (isHidden) { + return acc; + } + return [...acc, pointGeometry]; + }, + [] as PointGeometry[], + ); return { pointGeometries, indexedGeometries, @@ -216,9 +234,12 @@ export function renderLine( lineGeometry: LineGeometry; indexedGeometries: Map; } { + const isLogScale = isLogarithmicScale(yScale); + const pathGenerator = line() .x((datum: DataSeriesDatum) => xScale.scale(datum.x)) .y((datum: DataSeriesDatum) => yScale.scale(datum.y1)) + .defined((datum: DataSeriesDatum) => datum.y1 !== null && !(isLogScale && datum.y1 <= 0)) .curve(getCurveFactory(curve)); const y = 0; const x = shift; @@ -263,10 +284,18 @@ export function renderArea( areaGeometry: AreaGeometry; indexedGeometries: Map; } { + const isLogScale = isLogarithmicScale(yScale); + const pathGenerator = area() .x((datum: DataSeriesDatum) => xScale.scale(datum.x)) .y1((datum: DataSeriesDatum) => yScale.scale(datum.y1)) - .y0((datum: DataSeriesDatum) => yScale.scale(datum.y0)) + .y0((datum: DataSeriesDatum) => { + if (isLogScale && datum.y0 <= 0) { + return yScale.range[0]; + } + return yScale.scale(datum.y0); + }) + .defined((datum: DataSeriesDatum) => datum.y1 !== null && !(isLogScale && datum.y1 <= 0)) .curve(getCurveFactory(curve)); const { lineGeometry, indexedGeometries } = renderLine( shift, diff --git a/src/lib/series/utils/test_dataset_tsvb.ts b/src/lib/series/utils/test_dataset_tsvb.ts new file mode 100644 index 0000000000..beb429e4ce --- /dev/null +++ b/src/lib/series/utils/test_dataset_tsvb.ts @@ -0,0 +1,1055 @@ +export const TSVB_DATASET = { + id: '61ca57f0-469d-11e7-af02-69e470af7417', + series: [ + { + id: '61ca57f1-469d-11e7-af02-69e470af7417:jpg', + label: 'jpg', + color: 'rgb(104, 188, 0)', + data: [ + [1552830600000, 0], + [1552831200000, 0], + [1552831800000, 0], + [1552832400000, 0], + [1552833000000, 0], + [1552833600000, 0], + [1552834200000, 0], + [1552834800000, 0], + [1552835400000, 0], + [1552836000000, 0], + [1552836600000, 0], + [1552837200000, 0], + [1552837800000, 0], + [1552838400000, 0], + [1552839000000, 0], + [1552839600000, 0], + [1552840200000, 0], + [1552840800000, 0], + [1552841400000, 0], + [1552842000000, 0], + [1552842600000, 0], + [1552843200000, 0], + [1552843800000, 0], + [1552844400000, 0], + [1552845000000, 0], + [1552845600000, 0], + [1552846200000, 0], + [1552846800000, 0], + [1552847400000, 0], + [1552848000000, 0], + [1552848600000, 0], + [1552849200000, 0], + [1552849800000, 0], + [1552850400000, 0], + [1552851000000, 0], + [1552851600000, 0], + [1552852200000, 0], + [1552852800000, 0], + [1552853400000, 0], + [1552854000000, 0], + [1552854600000, 0], + [1552855200000, 0], + [1552855800000, 0], + [1552856400000, 6], + [1552857000000, 0], + [1552857600000, 0], + [1552858200000, 0], + [1552858800000, 1], + [1552859400000, 1], + [1552860000000, 0], + [1552860600000, 1], + [1552861200000, 1], + [1552861800000, 1], + [1552862400000, 0], + [1552863000000, 2], + [1552863600000, 1], + [1552864200000, 0], + [1552864800000, 1], + [1552865400000, 4], + [1552866000000, 6], + [1552866600000, 6], + [1552867200000, 4], + [1552867800000, 7], + [1552868400000, 3], + [1552869000000, 20], + [1552869600000, 30], + [1552870200000, 40], + [1552870800000, null], + [1552871400000, 5], + [1552872000000, 6], + [1552872600000, 12], + [1552873200000, 0], + [1552873800000, 10], + [1552874400000, 10], + [1552875000000, 13], + [1552875600000, 8], + [1552876200000, 13], + [1552876800000, 10], + [1552877400000, 10], + [1552878000000, 20], + [1552878600000, 16], + [1552879200000, 16], + [1552879800000, 15], + [1552880400000, 21], + [1552881000000, 19], + [1552881600000, 29], + [1552882200000, 31], + [1552882800000, 28], + [1552883400000, 33], + [1552884000000, 30], + [1552884600000, 29], + [1552885200000, 24], + [1552885800000, 35], + [1552886400000, 33], + [1552887000000, 32], + [1552887600000, 28], + [1552888200000, 48], + [1552888800000, 44], + [1552889400000, 26], + [1552890000000, 44], + [1552890600000, 65], + [1552891200000, 42], + [1552891800000, 49], + [1552892400000, 51], + [1552893000000, 59], + [1552893600000, 47], + [1552894200000, 47], + [1552894800000, 54], + [1552895400000, 48], + [1552896000000, 61], + [1552896600000, 63], + [1552897200000, 59], + [1552897800000, 58], + [1552898400000, 52], + [1552899000000, 61], + [1552899600000, 42], + [1552900200000, 48], + [1552900800000, 47], + [1552901400000, 52], + [1552902000000, 67], + [1552902600000, 49], + [1552903200000, 56], + [1552903800000, 36], + [1552904400000, 38], + [1552905000000, 42], + [1552905600000, 59], + [1552906200000, 41], + [1552906800000, 32], + [1552907400000, 48], + [1552908000000, 41], + [1552908600000, 41], + [1552909200000, 44], + [1552909800000, 46], + [1552910400000, 32], + [1552911000000, 40], + [1552911600000, 33], + [1552912200000, 30], + [1552912800000, 33], + [1552913400000, 31], + [1552914000000, 35], + [1552914600000, 22], + [1552915200000, 26], + [1552915800000, 22], + [1552916400000, 14], + [1552917000000, 22], + [1552917600000, 20], + [1552918200000, 13], + [1552918800000, 21], + [1552919400000, 14], + [1552920000000, 15], + [1552920600000, 13], + [1552921200000, 16], + [1552921800000, 14], + [1552922400000, 12], + [1552923000000, 10], + [1552923600000, 7], + [1552924200000, 12], + [1552924800000, 3], + [1552925400000, 0], + [1552926000000, 3], + [1552926600000, 6], + [1552927200000, 6], + [1552927800000, 7], + [1552928400000, 10], + [1552929000000, 4], + [1552929600000, 6], + [1552930200000, 9], + [1552930800000, 4], + [1552931400000, 2], + [1552932000000, 1], + [1552932600000, 3], + [1552933200000, 4], + [1552933800000, 6], + [1552934400000, 1], + [1552935000000, 0], + [1552935600000, 0], + [1552936200000, 0], + [1552936800000, 1], + [1552937400000, 1], + [1552938000000, 0], + [1552938600000, 1], + [1552939200000, 0], + [1552939800000, 0], + [1552940400000, 1], + [1552941000000, 0], + [1552941600000, 0], + [1552942200000, 0], + [1552942800000, 2], + [1552943400000, 0], + [1552944000000, 0], + [1552944600000, 1], + [1552945200000, 0], + [1552945800000, 2], + [1552946400000, 1], + [1552947000000, 0], + [1552947600000, 1], + [1552948200000, 1], + [1552948800000, 1], + [1552949400000, 2], + ], + stack: false, + lines: { show: true, fill: 0.5, lineWidth: 1, steps: false }, + points: { show: true, radius: 1, lineWidth: 1 }, + bars: { show: false, fill: 0.5, lineWidth: 1 }, + }, + { + id: '61ca57f1-469d-11e7-af02-69e470af7417:css', + label: 'css', + color: 'rgb(77, 138, 0)', + data: [ + [1552830600000, 0], + [1552831200000, 0], + [1552831800000, 0], + [1552832400000, 0], + [1552833000000, 0], + [1552833600000, 0], + [1552834200000, 0], + [1552834800000, 0], + [1552835400000, 0], + [1552836000000, 0], + [1552836600000, 0], + [1552837200000, 0], + [1552837800000, 0], + [1552838400000, 0], + [1552839000000, 0], + [1552839600000, 0], + [1552840200000, 0], + [1552840800000, 0], + [1552841400000, 0], + [1552842000000, 0], + [1552842600000, 0], + [1552843200000, 0], + [1552843800000, 0], + [1552844400000, 0], + [1552845000000, 0], + [1552845600000, 0], + [1552846200000, 0], + [1552846800000, 0], + [1552847400000, 0], + [1552848000000, 0], + [1552848600000, 0], + [1552849200000, 0], + [1552849800000, 0], + [1552850400000, 0], + [1552851000000, 0], + [1552851600000, 0], + [1552852200000, 0], + [1552852800000, 0], + [1552853400000, 0], + [1552854000000, 0], + [1552854600000, 0], + [1552855200000, 0], + [1552855800000, 0], + [1552856400000, 0], + [1552857000000, 0], + [1552857600000, 0], + [1552858200000, 1], + [1552858800000, 0], + [1552859400000, 0], + [1552860000000, 1], + [1552860600000, 0], + [1552861200000, 0], + [1552861800000, 2], + [1552862400000, 0], + [1552863000000, 0], + [1552863600000, 1], + [1552864200000, 0], + [1552864800000, 1], + [1552865400000, 1], + [1552866000000, 0], + [1552866600000, 0], + [1552867200000, 2], + [1552867800000, 0], + [1552868400000, 4], + [1552869000000, 0], + [1552869600000, 1], + [1552870200000, 0], + [1552870800000, 2], + [1552871400000, 2], + [1552872000000, 2], + [1552872600000, 1], + [1552873200000, 0], + [1552873800000, 2], + [1552874400000, 1], + [1552875000000, 2], + [1552875600000, 4], + [1552876200000, 4], + [1552876800000, 4], + [1552877400000, 3], + [1552878000000, 3], + [1552878600000, 3], + [1552879200000, 0], + [1552879800000, 3], + [1552880400000, 4], + [1552881000000, 4], + [1552881600000, 4], + [1552882200000, 8], + [1552882800000, 7], + [1552883400000, 7], + [1552884000000, 3], + [1552884600000, 8], + [1552885200000, 6], + [1552885800000, 6], + [1552886400000, 8], + [1552887000000, 11], + [1552887600000, 7], + [1552888200000, 8], + [1552888800000, 7], + [1552889400000, 11], + [1552890000000, 16], + [1552890600000, 14], + [1552891200000, 10], + [1552891800000, 12], + [1552892400000, 7], + [1552893000000, 15], + [1552893600000, 13], + [1552894200000, 9], + [1552894800000, 16], + [1552895400000, 15], + [1552896000000, 14], + [1552896600000, 9], + [1552897200000, 10], + [1552897800000, 15], + [1552898400000, 15], + [1552899000000, 13], + [1552899600000, 18], + [1552900200000, 17], + [1552900800000, 18], + [1552901400000, 18], + [1552902000000, 6], + [1552902600000, 19], + [1552903200000, 20], + [1552903800000, 14], + [1552904400000, 11], + [1552905000000, 7], + [1552905600000, 20], + [1552906200000, 11], + [1552906800000, 13], + [1552907400000, 8], + [1552908000000, 15], + [1552908600000, 10], + [1552909200000, 13], + [1552909800000, 16], + [1552910400000, 11], + [1552911000000, 11], + [1552911600000, 11], + [1552912200000, 7], + [1552912800000, 10], + [1552913400000, 6], + [1552914000000, 4], + [1552914600000, 6], + [1552915200000, 4], + [1552915800000, 5], + [1552916400000, 7], + [1552917000000, 7], + [1552917600000, 5], + [1552918200000, 2], + [1552918800000, 3], + [1552919400000, 4], + [1552920000000, 3], + [1552920600000, 4], + [1552921200000, 1], + [1552921800000, 4], + [1552922400000, 4], + [1552923000000, 2], + [1552923600000, 3], + [1552924200000, 3], + [1552924800000, 2], + [1552925400000, 0], + [1552926000000, 1], + [1552926600000, 0], + [1552927200000, 2], + [1552927800000, 4], + [1552928400000, 2], + [1552929000000, 2], + [1552929600000, 0], + [1552930200000, 0], + [1552930800000, 0], + [1552931400000, 2], + [1552932000000, 0], + [1552932600000, 1], + [1552933200000, 1], + [1552933800000, 0], + [1552934400000, 1], + [1552935000000, 0], + [1552935600000, 0], + [1552936200000, 0], + [1552936800000, 2], + [1552937400000, 0], + [1552938000000, 0], + [1552938600000, 0], + [1552939200000, 0], + [1552939800000, 0], + [1552940400000, 0], + [1552941000000, 0], + [1552941600000, 1], + [1552942200000, 0], + [1552942800000, 1], + [1552943400000, 0], + [1552944000000, 0], + [1552944600000, 0], + [1552945200000, 0], + [1552945800000, 0], + [1552946400000, 1], + [1552947000000, 1], + [1552947600000, 0], + [1552948200000, 0], + [1552948800000, 1], + [1552949400000, 0], + ], + stack: false, + lines: { show: true, fill: 0.5, lineWidth: 1, steps: false }, + points: { show: true, radius: 1, lineWidth: 1 }, + bars: { show: false, fill: 0.5, lineWidth: 1 }, + }, + { + id: '61ca57f1-469d-11e7-af02-69e470af7417:png', + label: 'png', + color: 'rgb(49, 89, 0)', + data: [ + [1552830600000, 0], + [1552831200000, 0], + [1552831800000, 0], + [1552832400000, 0], + [1552833000000, 0], + [1552833600000, 0], + [1552834200000, 0], + [1552834800000, 0], + [1552835400000, 0], + [1552836000000, 0], + [1552836600000, 0], + [1552837200000, 0], + [1552837800000, 0], + [1552838400000, 0], + [1552839000000, 0], + [1552839600000, 0], + [1552840200000, 0], + [1552840800000, 0], + [1552841400000, 0], + [1552842000000, 0], + [1552842600000, 0], + [1552843200000, 0], + [1552843800000, 0], + [1552844400000, 0], + [1552845000000, 0], + [1552845600000, 0], + [1552846200000, 0], + [1552846800000, 0], + [1552847400000, 0], + [1552848000000, 0], + [1552848600000, 0], + [1552849200000, 0], + [1552849800000, 0], + [1552850400000, 0], + [1552851000000, 0], + [1552851600000, 0], + [1552852200000, 0], + [1552852800000, 0], + [1552853400000, 0], + [1552854000000, 0], + [1552854600000, 0], + [1552855200000, 0], + [1552855800000, 0], + [1552856400000, 2], + [1552857000000, 0], + [1552857600000, 0], + [1552858200000, 0], + [1552858800000, 0], + [1552859400000, 0], + [1552860000000, 1], + [1552860600000, 1], + [1552861200000, 0], + [1552861800000, 0], + [1552862400000, 1], + [1552863000000, 0], + [1552863600000, 1], + [1552864200000, 1], + [1552864800000, 0], + [1552865400000, 0], + [1552866000000, 0], + [1552866600000, 1], + [1552867200000, 0], + [1552867800000, 2], + [1552868400000, 0], + [1552869000000, 0], + [1552869600000, 0], + [1552870200000, 0], + [1552870800000, 2], + [1552871400000, 3], + [1552872000000, 0], + [1552872600000, 0], + [1552873200000, 0], + [1552873800000, 0], + [1552874400000, 0], + [1552875000000, 2], + [1552875600000, 4], + [1552876200000, 0], + [1552876800000, 7], + [1552877400000, 0], + [1552878000000, 2], + [1552878600000, 0], + [1552879200000, 2], + [1552879800000, 4], + [1552880400000, 0], + [1552881000000, 2], + [1552881600000, 7], + [1552882200000, 4], + [1552882800000, 2], + [1552883400000, 4], + [1552884000000, 2], + [1552884600000, 6], + [1552885200000, 4], + [1552885800000, 5], + [1552886400000, 2], + [1552887000000, 7], + [1552887600000, 7], + [1552888200000, 5], + [1552888800000, 2], + [1552889400000, 1], + [1552890000000, 10], + [1552890600000, 9], + [1552891200000, 5], + [1552891800000, 10], + [1552892400000, 5], + [1552893000000, 7], + [1552893600000, 14], + [1552894200000, 10], + [1552894800000, 3], + [1552895400000, 11], + [1552896000000, 4], + [1552896600000, 15], + [1552897200000, 13], + [1552897800000, 15], + [1552898400000, 10], + [1552899000000, 4], + [1552899600000, 7], + [1552900200000, 12], + [1552900800000, 6], + [1552901400000, 9], + [1552902000000, 12], + [1552902600000, 3], + [1552903200000, 11], + [1552903800000, 10], + [1552904400000, 9], + [1552905000000, 6], + [1552905600000, 10], + [1552906200000, 5], + [1552906800000, 7], + [1552907400000, 9], + [1552908000000, 6], + [1552908600000, 7], + [1552909200000, 2], + [1552909800000, 3], + [1552910400000, 8], + [1552911000000, 2], + [1552911600000, 4], + [1552912200000, 6], + [1552912800000, 1], + [1552913400000, 6], + [1552914000000, 3], + [1552914600000, 2], + [1552915200000, 6], + [1552915800000, 6], + [1552916400000, 4], + [1552917000000, 3], + [1552917600000, 3], + [1552918200000, 1], + [1552918800000, 2], + [1552919400000, 4], + [1552920000000, 4], + [1552920600000, 2], + [1552921200000, 3], + [1552921800000, 1], + [1552922400000, 4], + [1552923000000, 1], + [1552923600000, 3], + [1552924200000, 1], + [1552924800000, 0], + [1552925400000, 0], + [1552926000000, 1], + [1552926600000, 1], + [1552927200000, 0], + [1552927800000, 0], + [1552928400000, 1], + [1552929000000, 1], + [1552929600000, 1], + [1552930200000, 0], + [1552930800000, 0], + [1552931400000, 0], + [1552932000000, 0], + [1552932600000, 0], + [1552933200000, 0], + [1552933800000, 0], + [1552934400000, 0], + [1552935000000, 0], + [1552935600000, 0], + [1552936200000, 0], + [1552936800000, 0], + [1552937400000, 0], + [1552938000000, 0], + [1552938600000, 0], + [1552939200000, 0], + [1552939800000, 0], + [1552940400000, 0], + [1552941000000, 0], + [1552941600000, 0], + [1552942200000, 0], + [1552942800000, 0], + [1552943400000, 0], + [1552944000000, 0], + [1552944600000, 0], + [1552945200000, 0], + [1552945800000, 0], + [1552946400000, 0], + [1552947000000, 1], + [1552947600000, 0], + [1552948200000, 1], + [1552948800000, 0], + [1552949400000, 1], + ], + stack: false, + lines: { show: true, fill: 0.5, lineWidth: 1, steps: false }, + points: { show: true, radius: 1, lineWidth: 1 }, + bars: { show: false, fill: 0.5, lineWidth: 1 }, + }, + { + id: '61ca57f1-469d-11e7-af02-69e470af7417:gif', + label: 'gif', + color: 'rgb(22, 39, 0)', + data: [ + [1552830600000, 0], + [1552831200000, 0], + [1552831800000, 0], + [1552832400000, 0], + [1552833000000, 0], + [1552833600000, 0], + [1552834200000, 0], + [1552834800000, 0], + [1552835400000, 0], + [1552836000000, 0], + [1552836600000, 0], + [1552837200000, 0], + [1552837800000, 0], + [1552838400000, 0], + [1552839000000, 0], + [1552839600000, 0], + [1552840200000, 0], + [1552840800000, 0], + [1552841400000, 0], + [1552842000000, 0], + [1552842600000, 0], + [1552843200000, 0], + [1552843800000, 0], + [1552844400000, 0], + [1552845000000, 0], + [1552845600000, 0], + [1552846200000, 0], + [1552846800000, 0], + [1552847400000, 0], + [1552848000000, 0], + [1552848600000, 0], + [1552849200000, 0], + [1552849800000, 0], + [1552850400000, 0], + [1552851000000, 0], + [1552851600000, 0], + [1552852200000, 0], + [1552852800000, 0], + [1552853400000, 0], + [1552854000000, 0], + [1552854600000, 0], + [1552855200000, 0], + [1552855800000, 0], + [1552856400000, 0], + [1552857000000, 0], + [1552857600000, 0], + [1552858200000, 0], + [1552858800000, 0], + [1552859400000, 0], + [1552860000000, 0], + [1552860600000, 0], + [1552861200000, 0], + [1552861800000, 0], + [1552862400000, 0], + [1552863000000, 0], + [1552863600000, 0], + [1552864200000, 0], + [1552864800000, 0], + [1552865400000, 0], + [1552866000000, 0], + [1552866600000, 0], + [1552867200000, 1], + [1552867800000, 0], + [1552868400000, 2], + [1552869000000, 1], + [1552869600000, 0], + [1552870200000, 1], + [1552870800000, 1], + [1552871400000, 2], + [1552872000000, 1], + [1552872600000, 2], + [1552873200000, 0], + [1552873800000, 1], + [1552874400000, 0], + [1552875000000, 0], + [1552875600000, 1], + [1552876200000, 1], + [1552876800000, 1], + [1552877400000, 2], + [1552878000000, 0], + [1552878600000, 2], + [1552879200000, 1], + [1552879800000, 2], + [1552880400000, 3], + [1552881000000, 2], + [1552881600000, 1], + [1552882200000, 2], + [1552882800000, 6], + [1552883400000, 4], + [1552884000000, 3], + [1552884600000, 5], + [1552885200000, 3], + [1552885800000, 3], + [1552886400000, 3], + [1552887000000, 3], + [1552887600000, 3], + [1552888200000, 3], + [1552888800000, 5], + [1552889400000, 1], + [1552890000000, 3], + [1552890600000, 4], + [1552891200000, 5], + [1552891800000, 4], + [1552892400000, 6], + [1552893000000, 4], + [1552893600000, 5], + [1552894200000, 5], + [1552894800000, 12], + [1552895400000, 7], + [1552896000000, 2], + [1552896600000, 8], + [1552897200000, 8], + [1552897800000, 5], + [1552898400000, 6], + [1552899000000, 8], + [1552899600000, 6], + [1552900200000, 3], + [1552900800000, 8], + [1552901400000, 4], + [1552902000000, 3], + [1552902600000, 9], + [1552903200000, 6], + [1552903800000, 14], + [1552904400000, 3], + [1552905000000, 7], + [1552905600000, 3], + [1552906200000, 4], + [1552906800000, 3], + [1552907400000, 5], + [1552908000000, 2], + [1552908600000, 3], + [1552909200000, 1], + [1552909800000, 2], + [1552910400000, 2], + [1552911000000, 5], + [1552911600000, 2], + [1552912200000, 1], + [1552912800000, 4], + [1552913400000, 3], + [1552914000000, 3], + [1552914600000, 4], + [1552915200000, 1], + [1552915800000, 4], + [1552916400000, 2], + [1552917000000, 3], + [1552917600000, 2], + [1552918200000, 2], + [1552918800000, 2], + [1552919400000, 0], + [1552920000000, 1], + [1552920600000, 2], + [1552921200000, 1], + [1552921800000, 4], + [1552922400000, 0], + [1552923000000, 0], + [1552923600000, 0], + [1552924200000, 0], + [1552924800000, 0], + [1552925400000, 0], + [1552926000000, 1], + [1552926600000, 2], + [1552927200000, 0], + [1552927800000, 0], + [1552928400000, 0], + [1552929000000, 0], + [1552929600000, 1], + [1552930200000, 0], + [1552930800000, 0], + [1552931400000, 0], + [1552932000000, 1], + [1552932600000, 1], + [1552933200000, 0], + [1552933800000, 0], + [1552934400000, 0], + [1552935000000, 0], + [1552935600000, 0], + [1552936200000, 0], + [1552936800000, 0], + [1552937400000, 0], + [1552938000000, 0], + [1552938600000, 0], + [1552939200000, 0], + [1552939800000, 0], + [1552940400000, 0], + [1552941000000, 0], + [1552941600000, 0], + [1552942200000, 0], + [1552942800000, 0], + [1552943400000, 0], + [1552944000000, 0], + [1552944600000, 0], + [1552945200000, 0], + [1552945800000, 0], + [1552946400000, 0], + [1552947000000, 0], + [1552947600000, 0], + [1552948200000, 0], + [1552948800000, 0], + [1552949400000, 0], + ], + stack: false, + lines: { show: true, fill: 0.5, lineWidth: 1, steps: false }, + points: { show: true, radius: 1, lineWidth: 1 }, + bars: { show: false, fill: 0.5, lineWidth: 1 }, + }, + { + id: '61ca57f1-469d-11e7-af02-69e470af7417:php', + label: 'php', + color: 'rgb(0, 0, 0)', + data: [ + [1552830600000, 0], + [1552831200000, 0], + [1552831800000, 0], + [1552832400000, 0], + [1552833000000, 0], + [1552833600000, 0], + [1552834200000, 0], + [1552834800000, 0], + [1552835400000, 0], + [1552836000000, 0], + [1552836600000, 0], + [1552837200000, 0], + [1552837800000, 0], + [1552838400000, 0], + [1552839000000, 0], + [1552839600000, 0], + [1552840200000, 0], + [1552840800000, 0], + [1552841400000, 0], + [1552842000000, 0], + [1552842600000, 0], + [1552843200000, 0], + [1552843800000, 0], + [1552844400000, 0], + [1552845000000, 0], + [1552845600000, 0], + [1552846200000, 0], + [1552846800000, 0], + [1552847400000, 0], + [1552848000000, 0], + [1552848600000, 0], + [1552849200000, 0], + [1552849800000, 0], + [1552850400000, 0], + [1552851000000, 0], + [1552851600000, 0], + [1552852200000, 0], + [1552852800000, 0], + [1552853400000, 0], + [1552854000000, 0], + [1552854600000, 0], + [1552855200000, 0], + [1552855800000, 0], + [1552856400000, 0], + [1552857000000, 0], + [1552857600000, 0], + [1552858200000, 0], + [1552858800000, 0], + [1552859400000, 0], + [1552860000000, 0], + [1552860600000, 0], + [1552861200000, 0], + [1552861800000, 0], + [1552862400000, 0], + [1552863000000, 0], + [1552863600000, 0], + [1552864200000, 0], + [1552864800000, 1], + [1552865400000, 0], + [1552866000000, 0], + [1552866600000, 0], + [1552867200000, 0], + [1552867800000, 0], + [1552868400000, 0], + [1552869000000, 0], + [1552869600000, 0], + [1552870200000, 0], + [1552870800000, 0], + [1552871400000, 1], + [1552872000000, 1], + [1552872600000, 1], + [1552873200000, 0], + [1552873800000, 1], + [1552874400000, 0], + [1552875000000, 0], + [1552875600000, 0], + [1552876200000, 0], + [1552876800000, 0], + [1552877400000, 3], + [1552878000000, 0], + [1552878600000, 0], + [1552879200000, 0], + [1552879800000, 0], + [1552880400000, 1], + [1552881000000, 1], + [1552881600000, 1], + [1552882200000, 1], + [1552882800000, 1], + [1552883400000, 2], + [1552884000000, 0], + [1552884600000, 1], + [1552885200000, 1], + [1552885800000, 1], + [1552886400000, 0], + [1552887000000, 1], + [1552887600000, 5], + [1552888200000, 2], + [1552888800000, 1], + [1552889400000, 4], + [1552890000000, 1], + [1552890600000, 2], + [1552891200000, 4], + [1552891800000, 8], + [1552892400000, 3], + [1552893000000, 4], + [1552893600000, 3], + [1552894200000, 2], + [1552894800000, 0], + [1552895400000, 5], + [1552896000000, 3], + [1552896600000, 4], + [1552897200000, 2], + [1552897800000, 1], + [1552898400000, 2], + [1552899000000, 2], + [1552899600000, 1], + [1552900200000, 3], + [1552900800000, 1], + [1552901400000, 1], + [1552902000000, 3], + [1552902600000, 4], + [1552903200000, 2], + [1552903800000, 4], + [1552904400000, 4], + [1552905000000, 4], + [1552905600000, 0], + [1552906200000, 5], + [1552906800000, 2], + [1552907400000, 5], + [1552908000000, 3], + [1552908600000, 0], + [1552909200000, 3], + [1552909800000, 0], + [1552910400000, 4], + [1552911000000, 1], + [1552911600000, 1], + [1552912200000, 0], + [1552912800000, 0], + [1552913400000, 2], + [1552914000000, 1], + [1552914600000, 2], + [1552915200000, 0], + [1552915800000, 0], + [1552916400000, 0], + [1552917000000, 1], + [1552917600000, 0], + [1552918200000, 1], + [1552918800000, 0], + [1552919400000, 2], + [1552920000000, 1], + [1552920600000, 0], + [1552921200000, 0], + [1552921800000, 0], + [1552922400000, 3], + [1552923000000, 0], + [1552923600000, 0], + [1552924200000, 0], + [1552924800000, 0], + [1552925400000, 0], + [1552926000000, 0], + [1552926600000, 0], + [1552927200000, 0], + [1552927800000, 0], + [1552928400000, 0], + [1552929000000, 0], + [1552929600000, 1], + [1552930200000, 0], + [1552930800000, 0], + [1552931400000, 0], + [1552932000000, 0], + [1552932600000, 0], + [1552933200000, 0], + [1552933800000, 0], + [1552934400000, 0], + [1552935000000, 0], + [1552935600000, 0], + [1552936200000, 1], + [1552936800000, 0], + [1552937400000, 0], + [1552938000000, 0], + [1552938600000, 0], + [1552939200000, 0], + [1552939800000, 0], + [1552940400000, 0], + [1552941000000, 0], + [1552941600000, 0], + [1552942200000, 0], + [1552942800000, 0], + [1552943400000, 0], + [1552944000000, 0], + [1552944600000, 0], + [1552945200000, 0], + [1552945800000, 0], + [1552946400000, 0], + [1552947000000, 0], + [1552947600000, 0], + [1552948200000, 0], + [1552948800000, 0], + [1552949400000, 1], + ], + stack: false, + lines: { show: true, fill: 0.5, lineWidth: 1, steps: false }, + points: { show: true, radius: 1, lineWidth: 1 }, + bars: { show: false, fill: 0.5, lineWidth: 1 }, + }, + ], +}; diff --git a/src/lib/utils/scales/scale_continuous.test.ts b/src/lib/utils/scales/scale_continuous.test.ts index c7b7121b54..cf7b9b1f1e 100644 --- a/src/lib/utils/scales/scale_continuous.test.ts +++ b/src/lib/utils/scales/scale_continuous.test.ts @@ -1,5 +1,6 @@ import { DateTime } from 'luxon'; -import { ScaleContinuous } from './scale_continuous'; +import { ScaleBand } from './scale_band'; +import { isLogarithmicScale, ScaleContinuous } from './scale_continuous'; import { ScaleType } from './scales'; describe.only('Scale Continuous', () => { @@ -35,4 +36,18 @@ describe.only('Scale Continuous', () => { expect(scale.invert(50)).toBe(midTime.toMillis()); expect(scale.invert(100)).toBe(endTime.toMillis()); }); + test('check if a scale is log scale', () => { + const domain = [0, 2]; + const range: [number, number] = [0, 100]; + const scaleLinear = new ScaleContinuous(domain, range, ScaleType.Linear); + const scaleLog = new ScaleContinuous(domain, range, ScaleType.Log); + const scaleTime = new ScaleContinuous(domain, range, ScaleType.Time); + const scaleSqrt = new ScaleContinuous(domain, range, ScaleType.Sqrt); + const scaleBand = new ScaleBand(domain, range); + expect(isLogarithmicScale(scaleLinear)).toBe(false); + expect(isLogarithmicScale(scaleLog)).toBe(true); + expect(isLogarithmicScale(scaleTime)).toBe(false); + expect(isLogarithmicScale(scaleSqrt)).toBe(false); + expect(isLogarithmicScale(scaleBand)).toBe(false); + }); }); diff --git a/src/lib/utils/scales/scale_continuous.ts b/src/lib/utils/scales/scale_continuous.ts index 9764835da1..ca8813e06d 100644 --- a/src/lib/utils/scales/scale_continuous.ts +++ b/src/lib/utils/scales/scale_continuous.ts @@ -143,6 +143,10 @@ export function isContinuousScale(scale: Scale): scale is ScaleContinuous { return scale.type !== ScaleType.Ordinal; } +export function isLogarithmicScale(scale: Scale) { + return scale.type === ScaleType.Log; +} + function invertValue(invertedValue: number, minInterval: number, stepType?: StepType) { if (minInterval > 0) { switch (stepType) { diff --git a/stories/line_chart.tsx b/stories/line_chart.tsx index 10d19adb4f..921a6644ca 100644 --- a/stories/line_chart.tsx +++ b/stories/line_chart.tsx @@ -14,6 +14,7 @@ import { timeFormatter, } from '../src/'; import { KIBANA_METRICS } from '../src/lib/series/utils/test_dataset_kibana'; +import { TSVB_DATASET } from '../src/lib/series/utils/test_dataset_tsvb'; const dateFormatter = timeFormatter(niceTimeFormatByDay(1)); storiesOf('Line Chart', module) @@ -316,4 +317,38 @@ storiesOf('Line Chart', module) /> ); + }) + .add('multi series with log values (limit 0 or negative values)', () => { + return ( + + + + `${Number(d).toFixed(0)}%`} + /> + {TSVB_DATASET.series.map((series) => { + return ( + + ); + })} + + ); });