Skip to content

Commit

Permalink
fix(ticks): fill in additional ticks for histogram (#251)
Browse files Browse the repository at this point in the history
  • Loading branch information
emmacunningham authored and markov00 committed Jul 5, 2019
1 parent 1bfb430 commit af92736
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 33 deletions.
114 changes: 84 additions & 30 deletions src/lib/axes/axis_utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,36 +206,90 @@ describe('Axis computational utils', () => {
expect(xScale).toBeDefined();
});

test('should compute available ticks', () => {
const scale = getScaleForAxisSpec(verticalAxisSpec, xDomain, [yDomain], 0, 0, 100, 0);
const axisPositions = getAvailableTicks(verticalAxisSpec, scale!, 0, false);
const expectedAxisPositions = [
{ label: '0', position: 100, value: 0 },
{ label: '0.1', position: 90, value: 0.1 },
{ label: '0.2', position: 80, value: 0.2 },
{ label: '0.3', position: 70, value: 0.3 },
{ label: '0.4', position: 60, value: 0.4 },
{ label: '0.5', position: 50, value: 0.5 },
{ label: '0.6', position: 40, value: 0.6 },
{ label: '0.7', position: 30, value: 0.7 },
{ label: '0.8', position: 20, value: 0.8 },
{ label: '0.9', position: 10, value: 0.9 },
{ label: '1', position: 0, value: 1 },
];
expect(axisPositions).toEqual(expectedAxisPositions);

// histogram mode axis ticks should add an additional tick
const xBandDomain: XDomain = {
type: 'xDomain',
scaleType: ScaleType.Linear,
domain: [0, 100],
isBandScale: true,
minInterval: 10,
};
const xScale = getScaleForAxisSpec(horizontalAxisSpec, xBandDomain, [yDomain], 1, 0, 100, 0);
const histogramAxisPositions = getAvailableTicks(horizontalAxisSpec, xScale!, 1, true);
const histogramTickLabels = histogramAxisPositions.map((tick: AxisTick) => tick.label);
expect(histogramTickLabels).toEqual(['0', '10', '20', '30', '40', '50', '60', '70', '80', '90', '100', '110']);
describe('getAvailableTicks', () => {
test('should compute to end of domain when histogram mode not enabled', () => {
const enableHistogramMode = false;
const scale = getScaleForAxisSpec(verticalAxisSpec, xDomain, [yDomain], 0, 0, 100, 0);
const axisPositions = getAvailableTicks(verticalAxisSpec, scale!, 0, enableHistogramMode);
const expectedAxisPositions = [
{ label: '0', position: 100, value: 0 },
{ label: '0.1', position: 90, value: 0.1 },
{ label: '0.2', position: 80, value: 0.2 },
{ label: '0.3', position: 70, value: 0.3 },
{ label: '0.4', position: 60, value: 0.4 },
{ label: '0.5', position: 50, value: 0.5 },
{ label: '0.6', position: 40, value: 0.6 },
{ label: '0.7', position: 30, value: 0.7 },
{ label: '0.8', position: 20, value: 0.8 },
{ label: '0.9', position: 10, value: 0.9 },
{ label: '1', position: 0, value: 1 },
];
expect(axisPositions).toEqual(expectedAxisPositions);
});

test('should extend ticks to domain + minInterval in histogram mode for linear scale', () => {
const enableHistogramMode = true;
const xBandDomain: XDomain = {
type: 'xDomain',
scaleType: ScaleType.Linear,
domain: [0, 100],
isBandScale: true,
minInterval: 10,
};
const xScale = getScaleForAxisSpec(horizontalAxisSpec, xBandDomain, [yDomain], 1, 0, 100, 0);
const histogramAxisPositions = getAvailableTicks(horizontalAxisSpec, xScale!, 1, enableHistogramMode);
const histogramTickLabels = histogramAxisPositions.map(({ label }: AxisTick) => label);
expect(histogramTickLabels).toEqual(['0', '10', '20', '30', '40', '50', '60', '70', '80', '90', '100', '110']);
});

test('should extend ticks to domain + minInterval in histogram mode for time scale', () => {
const enableHistogramMode = true;
const xBandDomain: XDomain = {
type: 'xDomain',
scaleType: ScaleType.Time,
domain: [1560438420000, 1560438510000],
isBandScale: true,
minInterval: 90000,
};
const xScale = getScaleForAxisSpec(horizontalAxisSpec, xBandDomain, [yDomain], 1, 0, 100, 0);
const histogramAxisPositions = getAvailableTicks(horizontalAxisSpec, xScale!, 1, enableHistogramMode);
const histogramTickValues = histogramAxisPositions.map(({ value }: AxisTick) => value);

const expectedTickValues = [
1560438420000,
1560438435000,
1560438450000,
1560438465000,
1560438480000,
1560438495000,
1560438510000,
1560438525000,
1560438540000,
1560438555000,
1560438570000,
1560438585000,
1560438600000,
];

expect(histogramTickValues).toEqual(expectedTickValues);
});

test('should extend ticks to domain + minInterval in histogram mode for a scale with single datum', () => {
const enableHistogramMode = true;
const xBandDomain: XDomain = {
type: 'xDomain',
scaleType: ScaleType.Time,
domain: [1560438420000, 1560438420000], // a single datum scale will have the same value for domain start & end
isBandScale: true,
minInterval: 90000,
};
const xScale = getScaleForAxisSpec(horizontalAxisSpec, xBandDomain, [yDomain], 1, 0, 100, 0);
const histogramAxisPositions = getAvailableTicks(horizontalAxisSpec, xScale!, 1, enableHistogramMode);
const histogramTickValues = histogramAxisPositions.map(({ value }: AxisTick) => value);
const expectedTickValues = [1560438420000, 1560438510000];

expect(histogramTickValues).toEqual(expectedTickValues);
});
});
test('should compute visible ticks for a vertical axis', () => {
const allTicks = [
Expand Down
37 changes: 34 additions & 3 deletions src/lib/axes/axis_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,17 +383,47 @@ export function getAvailableTicks(
enableHistogramMode: boolean,
): AxisTick[] {
const ticks = scale.ticks();
const isSingleValueScale = scale.domain[0] - scale.domain[1] === 0;
const hasAdditionalTicks = enableHistogramMode && scale.bandwidth > 0;

if (enableHistogramMode && scale.bandwidth > 0) {
const finalTick = ticks[ticks.length - 1] + scale.minInterval;
ticks.push(finalTick);
if (hasAdditionalTicks) {
const lastComputedTick = ticks[ticks.length - 1];

if (!isSingleValueScale) {
const penultimateComputedTick = ticks[ticks.length - 2];
const computedTickDistance = lastComputedTick - penultimateComputedTick;
const numTicks = scale.minInterval / computedTickDistance;

for (let i = 1; i <= numTicks; i++) {
ticks.push(i * computedTickDistance + lastComputedTick);
}
}
}

const shift = totalBarsInCluster > 0 ? totalBarsInCluster : 1;

const band = scale.bandwidth / (1 - scale.barsPadding);
const halfPadding = (band - scale.bandwidth) / 2;
const offset = enableHistogramMode ? -halfPadding : (scale.bandwidth * shift) / 2;

if (isSingleValueScale && hasAdditionalTicks) {
const firstTickValue = ticks[0];
const firstTick = {
value: firstTickValue,
label: axisSpec.tickFormat(firstTickValue),
position: scale.scale(firstTickValue) + offset,
};

const lastTickValue = firstTickValue + scale.minInterval;
const lastTick = {
value: lastTickValue,
label: axisSpec.tickFormat(lastTickValue),
position: scale.bandwidth + halfPadding * 2,
};

return [firstTick, lastTick];
}

return ticks.map((tick) => {
return {
value: tick,
Expand Down Expand Up @@ -433,6 +463,7 @@ export function getVisibleTicks(allTicks: AxisTick[], axisSpec: AxisSpec, axisDi
}
}
}

return visibleTicks;
}

Expand Down
33 changes: 33 additions & 0 deletions stories/bar_chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1608,6 +1608,39 @@ storiesOf('Bar Chart', module)
</Chart>
);
})
.add('[test] single histogram bar chart', () => {
const formatter = timeFormatter(niceTimeFormatByDay(1));

const xDomain = {
minInterval: 60000,
};

return (
<Chart className={'story-chart'}>
<Settings xDomain={xDomain} />
<Axis
id={getAxisId('bottom')}
title={'timestamp per 1 minute'}
position={Position.Bottom}
showOverlappingTicks={true}
tickFormat={formatter}
/>
<Axis
id={getAxisId('left')}
title={KIBANA_METRICS.metrics.kibana_os_load[0].metric.title}
position={Position.Left}
/>
<HistogramBarSeries
id={getSpecId('bars')}
xScaleType={ScaleType.Linear}
yScaleType={ScaleType.Linear}
xAccessor={0}
yAccessors={[1]}
data={KIBANA_METRICS.metrics.kibana_os_load[0].data.slice(0, 1)}
/>
</Chart>
);
})
.add('stacked only grouped areas', () => {
const data1 = [[1, 2], [2, 2], [3, 3], [4, 5], [5, 5], [6, 3], [7, 8], [8, 2], [9, 1]];
const data2 = [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 4], [7, 3], [8, 2], [9, 4]];
Expand Down

0 comments on commit af92736

Please sign in to comment.