Skip to content

Commit

Permalink
Merge pull request #35 from redbearsam/feature/line-chart
Browse files Browse the repository at this point in the history
Added line chart
  • Loading branch information
matt-hooper authored Feb 12, 2019
2 parents 02940bd + bf6773a commit c457917
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 22 deletions.
2 changes: 1 addition & 1 deletion packages/perspective-viewer-d3fc/src/js/axis/crossAxis.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const scale = settings => {
}
};

const defaultScaleBand = () => minBandwidth(d3.scaleBand().padding(0.5));
const defaultScaleBand = () => minBandwidth(d3.scaleBand());

export const domain = settings => {
const accessData = extent => {
Expand Down
31 changes: 22 additions & 9 deletions packages/perspective-viewer-d3fc/src/js/axis/mainAxis.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,34 @@
*
*/
import * as d3 from "d3";
import * as fc from "d3fc";

export const scale = () => d3.scaleLinear();

export const domain = (settings, data) => {
// For multiple main values, we need to check the maximum and minimum (+ve and -ve)
const mainValueAccessors = aggFn => settings.mainValues.map(() => d => d.reduce((max, v) => aggFn(max, v.mainValue), 0));
const extent = getDataExtentFromArray(data);
return [extent[0] > 0 ? 0 : extent[0] * 1.1, extent[1] < 0 ? 0 : extent[1] * 1.1];
};

const accessors = settings.mainValues.length > 1 ? mainValueAccessors(Math.max).concat(mainValueAccessors(Math.min)) : [d => d.mainValue];
const getDataExtentFromArray = array => {
const dataExtent = array.map(getDataExtentFromValue);
const extent = flattenExtent(dataExtent);
return extent;
};

return fc
.extentLinear()
.include([0])
.pad([0, 0.1])
.accessors(accessors)(data.reduce((r, v) => r.concat(v), []));
const getDataExtentFromValue = value => {
if (Array.isArray(value)) {
return getDataExtentFromArray(value);
}
return [value.mainValue, value.mainValue];
};

export const label = settings => settings.mainValues.map(v => v.name).join(", ");

function flattenExtent(array) {
const withUndefined = fn => (a, b) => {
if (a === undefined) return b;
if (b === undefined) return a;
return fn(a, b);
};
return array.reduce((r, v) => [withUndefined(Math.min)(r[0], v[0]), withUndefined(Math.max)(r[1], v[1])], [undefined, undefined]);
}
7 changes: 5 additions & 2 deletions packages/perspective-viewer-d3fc/src/js/charts/bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
import * as fc from "d3fc";
import * as crossAxis from "../axis/crossAxis";
import * as mainAxis from "../axis/mainAxis";
import {barSeries, barColours} from "../series/barSeries";
import {barSeries} from "../series/barSeries";
import {seriesColours} from "../series/seriesColours";
import {groupAndStackData} from "../data/groupAndStackData";
import {legend, filterData} from "../legend/legend";

function barChart(container, settings) {
const data = groupAndStackData(settings, filterData(settings));
const colour = barColours(settings);
const colour = seriesColours(settings);
legend(container, settings, colour);

const series = fc
Expand All @@ -38,6 +39,8 @@ function barChart(container, settings) {
.yLabel(crossAxis.label(settings))
.plotArea(series);

chart.yPadding && chart.yPadding(0.5);

// render
container.datum(data).call(chart);
}
Expand Down
3 changes: 2 additions & 1 deletion packages/perspective-viewer-d3fc/src/js/charts/charts.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import barChart from "./bar";
import columnChart from "./column";
import lineChart from "./line";

const chartClasses = [barChart, columnChart];
const chartClasses = [barChart, columnChart, lineChart];
export default chartClasses;
7 changes: 5 additions & 2 deletions packages/perspective-viewer-d3fc/src/js/charts/column.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
import * as fc from "d3fc";
import * as crossAxis from "../axis/crossAxis";
import * as mainAxis from "../axis/mainAxis";
import {barSeries, barColours} from "../series/barSeries";
import {barSeries} from "../series/barSeries";
import {seriesColours} from "../series/seriesColours";
import {groupAndStackData} from "../data/groupAndStackData";
import {legend, filterData} from "../legend/legend";

function columnChart(container, settings) {
const data = groupAndStackData(settings, filterData(settings));
const colour = barColours(settings);
const colour = seriesColours(settings);
legend(container, settings, colour);

const series = fc
Expand All @@ -38,6 +39,8 @@ function columnChart(container, settings) {
.yLabel(mainAxis.label(settings))
.plotArea(series);

chart.xPadding && chart.xPadding(0.5);

// render
container.datum(data).call(chart);
}
Expand Down
44 changes: 44 additions & 0 deletions packages/perspective-viewer-d3fc/src/js/charts/line.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/******************************************************************************
*
* Copyright (c) 2017, the Perspective Authors.
*
* This file is part of the Perspective library, distributed under the terms of
* the Apache License 2.0. The full license can be found in the LICENSE file.
*
*/
import * as fc from "d3fc";
import * as crossAxis from "../axis/crossAxis";
import * as mainAxis from "../axis/mainAxis";
import {seriesColours} from "../series/seriesColours";
import {lineSeries} from "../series/lineSeries";
import {splitData} from "../data/splitData";
import {legend, filterData} from "../legend/legend";

function lineChart(container, settings) {
const data = splitData(settings, filterData(settings));
const colour = seriesColours(settings);
legend(container, settings, colour);

const series = fc.seriesSvgRepeat().series(lineSeries(settings, colour).orient("vertical"));

const chart = fc
.chartSvgCartesian(crossAxis.scale(settings), mainAxis.scale(settings))
.xDomain(crossAxis.domain(settings, data))
.xLabel(crossAxis.label(settings))
.yDomain(mainAxis.domain(settings, data))
.yOrient("left")
.yLabel(mainAxis.label(settings))
.plotArea(series);

chart.xAlign && chart.xPadding(1);

// render
container.datum(data).call(chart);
}
lineChart.plugin = {
type: "d3_y_line_2",
name: "[d3fc] Y Line Chart 2",
maxRenderSize: 25000
};

export default lineChart;
23 changes: 23 additions & 0 deletions packages/perspective-viewer-d3fc/src/js/data/splitData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/******************************************************************************
*
* Copyright (c) 2017, the Perspective Authors.
*
* This file is part of the Perspective library, distributed under the terms of
* the Apache License 2.0. The full license can be found in the LICENSE file.
*
*/
import {labelFunction} from "../axis/crossAxis";

export function splitData(settings, data) {
const labelfn = labelFunction(settings);

return data.map((col, i) => {
return Object.keys(col)
.filter(key => key !== "__ROW_PATH__")
.map(key => ({
key,
crossValue: labelfn(col, i),
mainValue: col[key]
}));
});
}
7 changes: 0 additions & 7 deletions packages/perspective-viewer-d3fc/src/js/series/barSeries.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
* the Apache License 2.0. The full license can be found in the LICENSE file.
*
*/
import * as d3 from "d3";
import * as fc from "d3fc";

export function barSeries(settings, colour) {
Expand All @@ -24,9 +23,3 @@ export function barSeries(settings, colour) {
.mainValue(d => d.mainValue)
.baseValue(d => d.baseValue);
}

export function barColours(settings) {
const col = settings.data && settings.data.length > 0 ? settings.data[0] : {};
const domain = Object.keys(col).filter(k => k !== "__ROW_PATH__");
return domain.length > 1 ? d3.scaleOrdinal(d3.schemeCategory10).domain(domain) : null;
}
21 changes: 21 additions & 0 deletions packages/perspective-viewer-d3fc/src/js/series/lineSeries.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/******************************************************************************
*
* Copyright (c) 2017, the Perspective Authors.
*
* This file is part of the Perspective library, distributed under the terms of
* the Apache License 2.0. The full license can be found in the LICENSE file.
*
*/
import * as fc from "d3fc";

export function lineSeries(settings, colour) {
let series = fc.seriesSvgLine();

if (colour) {
series = series.decorate(selection => {
selection.style("stroke", d => colour(d[0] && d[0].key));
});
}

return series.crossValue(d => d.crossValue).mainValue(d => d.mainValue);
}
15 changes: 15 additions & 0 deletions packages/perspective-viewer-d3fc/src/js/series/seriesColours.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/******************************************************************************
*
* Copyright (c) 2017, the Perspective Authors.
*
* This file is part of the Perspective library, distributed under the terms of
* the Apache License 2.0. The full license can be found in the LICENSE file.
*
*/
import * as d3 from "d3";

export function seriesColours(settings) {
const col = settings.data && settings.data.length > 0 ? settings.data[0] : {};
const domain = Object.keys(col).filter(k => k !== "__ROW_PATH__");
return domain.length > 1 ? d3.scaleOrdinal(d3.schemeCategory10).domain(domain) : null;
}
3 changes: 3 additions & 0 deletions packages/perspective-viewer-d3fc/src/less/chart.less
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
& .bar {
fill: rgb(31, 119, 180);
}
& .line {
stroke: rgb(31, 119, 180);
}
}

.label rect {
Expand Down

0 comments on commit c457917

Please sign in to comment.