Skip to content

Commit 5b16be6

Browse files
fix(domain): set domain bounds dependent on negative/positive values (#149)
1 parent 77a352c commit 5b16be6

File tree

3 files changed

+98
-5
lines changed

3 files changed

+98
-5
lines changed

src/lib/utils/domain.test.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { AccessorFn } from './accessor';
2-
import { computeContinuousDataDomain, computeOrdinalDataDomain, computeStackedContinuousDomain } from './domain';
2+
import {
3+
computeContinuousDataDomain,
4+
computeDomainExtent,
5+
computeOrdinalDataDomain,
6+
computeStackedContinuousDomain,
7+
} from './domain';
38

49
describe('utils/domain', () => {
510
test('should compute ordinal data domain: sort & remove nulls', () => {
@@ -151,4 +156,18 @@ describe('utils/domain', () => {
151156

152157
expect(stackedDataDomain).toEqual(expectedStackedDomain);
153158
});
159+
160+
test('should compute domain based on scaleToExtent', () => {
161+
// start & end are positive
162+
expect(computeDomainExtent([5, 10], true)).toEqual([5, 10]);
163+
expect(computeDomainExtent([5, 10], false)).toEqual([0, 10]);
164+
165+
// start & end are negative
166+
expect(computeDomainExtent([-15, -10], true)).toEqual([-15, -10]);
167+
expect(computeDomainExtent([-15, -10], false)).toEqual([-15, 0]);
168+
169+
// start is negative, end is positive
170+
expect(computeDomainExtent([-15, 10], true)).toEqual([-15, 10]);
171+
expect(computeDomainExtent([-15, 10], false)).toEqual([-15, 10]);
172+
});
154173
});

src/lib/utils/domain.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,37 @@ export function computeOrdinalDataDomain(
4040
const uniqueValues = [...new Set(domain)];
4141
return sorted
4242
? uniqueValues.sort((a, b) => {
43-
return `${a}`.localeCompare(`${b}`);
44-
})
43+
return `${a}`.localeCompare(`${b}`);
44+
})
4545
: uniqueValues;
4646
}
4747

48+
export function computeDomainExtent(
49+
computedDomain: [number, number] | [undefined, undefined],
50+
scaleToExtent: boolean,
51+
): [number, number] {
52+
const [start, end] = computedDomain;
53+
54+
if (start != null && end != null) {
55+
if (start >= 0 && end >= 0) {
56+
return scaleToExtent ? [start, end] : [0, end];
57+
} else if (start < 0 && end < 0) {
58+
return scaleToExtent ? [start, end] : [start, 0];
59+
}
60+
return [start, end];
61+
}
62+
63+
// if any of the values are null
64+
return [0, 0];
65+
}
66+
4867
export function computeContinuousDataDomain(
4968
data: any[],
5069
accessor: AccessorFn,
5170
scaleToExtent = false,
5271
): number[] {
5372
const range = extent(data, accessor);
54-
return scaleToExtent ? range : [0, range[1] || 0];
73+
return computeDomainExtent(range, scaleToExtent);
5574
}
5675

5776
export function computeStackedContinuousDomain(

stories/bar_chart.tsx

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { boolean } from '@storybook/addon-knobs';
1+
import { boolean, select } from '@storybook/addon-knobs';
22
import { storiesOf } from '@storybook/react';
33
import { DateTime } from 'luxon';
44
import React from 'react';
@@ -831,6 +831,61 @@ storiesOf('Bar Chart', module)
831831
</Chart>
832832
);
833833
})
834+
.add('scale to extent', () => {
835+
const yScaleToDataExtent = boolean('yScaleDataToExtent', false);
836+
const mixed = [
837+
{ x: 3, y: 1 },
838+
{ x: 0, y: -4 },
839+
{ x: 2, y: 2 },
840+
{ x: 1, y: -3 },
841+
{ x: 2, y: 2 },
842+
{ x: 1, y: -3 },
843+
{ x: 3, y: 1 },
844+
];
845+
846+
const allPositive = mixed.map((datum) => ({ x: datum.x, y: Math.abs(datum.y) }));
847+
const allNegative = mixed.map((datum) => ({ x: datum.x, y: Math.abs(datum.y) * -1 }));
848+
849+
const dataChoice = select('data', {
850+
mixed: 'mixed',
851+
allPositive: 'all positive',
852+
allNegative: 'all negative',
853+
}, 'mixed');
854+
855+
let data = mixed;
856+
switch (dataChoice) {
857+
case 'all positive':
858+
data = allPositive;
859+
break;
860+
case 'all negative':
861+
data = allNegative;
862+
break;
863+
}
864+
865+
return (
866+
<Chart renderer="canvas" className={'story-chart'}>
867+
<Axis id={getAxisId('top')} position={Position.Top} title={'Top axis'} />
868+
<Axis
869+
id={getAxisId('left2')}
870+
title={'Left axis'}
871+
position={Position.Left}
872+
tickFormat={(d) => Number(d).toFixed(2)}
873+
/>
874+
875+
<BarSeries
876+
id={getSpecId('bars')}
877+
xScaleType={ScaleType.Linear}
878+
yScaleType={ScaleType.Linear}
879+
xAccessor="x"
880+
yAccessors={['y']}
881+
splitSeriesAccessors={['g']}
882+
stackAccessors={['x']}
883+
data={data}
884+
yScaleToDataExtent={yScaleToDataExtent}
885+
/>
886+
</Chart>
887+
);
888+
})
834889
.add('[test] - linear', () => {
835890
const data = [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 4], [7, 3], [8, 2], [9, 1]];
836891
return (

0 commit comments

Comments
 (0)