Skip to content

Commit

Permalink
feat(sankey): add sankey layout
Browse files Browse the repository at this point in the history
  • Loading branch information
hustcc committed Nov 27, 2020
1 parent 8e258c1 commit fe7aaa1
Show file tree
Hide file tree
Showing 7 changed files with 395 additions and 8 deletions.
122 changes: 122 additions & 0 deletions __tests__/data/sankey-energy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
export const ENERGY = {
nodes: [
{ name: "Agricultural 'waste'" },
{ name: 'Bio-conversion' },
{ name: 'Liquid' },
{ name: 'Losses' },
{ name: 'Solid' },
{ name: 'Gas' },
{ name: 'Biofuel imports' },
{ name: 'Biomass imports' },
{ name: 'Coal imports' },
{ name: 'Coal' },
{ name: 'Coal reserves' },
{ name: 'District heating' },
{ name: 'Industry' },
{ name: 'Heating and cooling - commercial' },
{ name: 'Heating and cooling - homes' },
{ name: 'Electricity grid' },
{ name: 'Over generation / exports' },
{ name: 'H2 conversion' },
{ name: 'Road transport' },
{ name: 'Agriculture' },
{ name: 'Rail transport' },
{ name: 'Lighting & appliances - commercial' },
{ name: 'Lighting & appliances - homes' },
{ name: 'Gas imports' },
{ name: 'Ngas' },
{ name: 'Gas reserves' },
{ name: 'Thermal generation' },
{ name: 'Geothermal' },
{ name: 'H2' },
{ name: 'Hydro' },
{ name: 'International shipping' },
{ name: 'Domestic aviation' },
{ name: 'International aviation' },
{ name: 'National navigation' },
{ name: 'Marine algae' },
{ name: 'Nuclear' },
{ name: 'Oil imports' },
{ name: 'Oil' },
{ name: 'Oil reserves' },
{ name: 'Other waste' },
{ name: 'Pumped heat' },
{ name: 'Solar PV' },
{ name: 'Solar Thermal' },
{ name: 'Solar' },
{ name: 'Tidal' },
{ name: 'UK land based bioenergy' },
{ name: 'Wave' },
{ name: 'Wind' },
],
links: [
{ source: 0, target: 1, value: 124.729 },
{ source: 1, target: 2, value: 0.597 },
{ source: 1, target: 3, value: 26.862 },
{ source: 1, target: 4, value: 280.322 },
{ source: 1, target: 5, value: 81.144 },
{ source: 6, target: 2, value: 35 },
{ source: 7, target: 4, value: 35 },
{ source: 8, target: 9, value: 11.606 },
{ source: 10, target: 9, value: 63.965 },
{ source: 9, target: 4, value: 75.571 },
{ source: 11, target: 12, value: 10.639 },
{ source: 11, target: 13, value: 22.505 },
{ source: 11, target: 14, value: 46.184 },
{ source: 15, target: 16, value: 104.453 },
{ source: 15, target: 14, value: 113.726 },
{ source: 15, target: 17, value: 27.14 },
{ source: 15, target: 12, value: 342.165 },
{ source: 15, target: 18, value: 37.797 },
{ source: 15, target: 19, value: 4.412 },
{ source: 15, target: 13, value: 40.858 },
{ source: 15, target: 3, value: 56.691 },
{ source: 15, target: 20, value: 7.863 },
{ source: 15, target: 21, value: 90.008 },
{ source: 15, target: 22, value: 93.494 },
{ source: 23, target: 24, value: 40.719 },
{ source: 25, target: 24, value: 82.233 },
{ source: 5, target: 13, value: 0.129 },
{ source: 5, target: 3, value: 1.401 },
{ source: 5, target: 26, value: 151.891 },
{ source: 5, target: 19, value: 2.096 },
{ source: 5, target: 12, value: 48.58 },
{ source: 27, target: 15, value: 7.013 },
{ source: 17, target: 28, value: 20.897 },
{ source: 17, target: 3, value: 6.242 },
{ source: 28, target: 18, value: 20.897 },
{ source: 29, target: 15, value: 6.995 },
{ source: 2, target: 12, value: 121.066 },
{ source: 2, target: 30, value: 128.69 },
{ source: 2, target: 18, value: 135.835 },
{ source: 2, target: 31, value: 14.458 },
{ source: 2, target: 32, value: 206.267 },
{ source: 2, target: 19, value: 3.64 },
{ source: 2, target: 33, value: 33.218 },
{ source: 2, target: 20, value: 4.413 },
{ source: 34, target: 1, value: 4.375 },
{ source: 24, target: 5, value: 122.952 },
{ source: 35, target: 26, value: 839.978 },
{ source: 36, target: 37, value: 504.287 },
{ source: 38, target: 37, value: 107.703 },
{ source: 37, target: 2, value: 611.99 },
{ source: 39, target: 4, value: 56.587 },
{ source: 39, target: 1, value: 77.81 },
{ source: 40, target: 14, value: 193.026 },
{ source: 40, target: 13, value: 70.672 },
{ source: 41, target: 15, value: 59.901 },
{ source: 42, target: 14, value: 19.263 },
{ source: 43, target: 42, value: 19.263 },
{ source: 43, target: 41, value: 59.901 },
{ source: 4, target: 19, value: 0.882 },
{ source: 4, target: 26, value: 400.12 },
{ source: 4, target: 12, value: 46.477 },
{ source: 26, target: 15, value: 525.531 },
{ source: 26, target: 3, value: 787.129 },
{ source: 26, target: 11, value: 79.329 },
{ source: 44, target: 15, value: 9.452 },
{ source: 45, target: 1, value: 182.01 },
{ source: 46, target: 15, value: 19.013 },
{ source: 47, target: 15, value: 289.366 },
],
};
49 changes: 49 additions & 0 deletions __tests__/unit/utils/transform/sankey-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { sankeyLeft, sankeyJustify } from 'd3-sankey';
import { sankeyLayout, getNodeAlignFunction, getDefaultOptions } from '../../../../src/utils/transform/sankey';
import { ENERGY } from '../../../data/sankey-energy';

describe('sankeyLayout', () => {
it('getNodeAlignFunction', () => {
expect(getNodeAlignFunction(null)).toBe(sankeyJustify);
expect(getNodeAlignFunction(undefined)).toBe(sankeyJustify);
// @ts-ignore
expect(getNodeAlignFunction('middle')).toBe(sankeyJustify);

expect(getNodeAlignFunction('left')).toBe(sankeyLeft);

const fn = jest.fn();
// @ts-ignore
expect(getNodeAlignFunction(fn)).toBe(fn);
});

it('getDefaultOptions', () => {
expect(getDefaultOptions({}).nodeAlign).toBe('justify');
expect(getDefaultOptions({}).nodePadding).toBe(0.03);
expect(getDefaultOptions({}).nodeWidth).toBe(0.008);
});

it('sankeyLayout', () => {
const data = sankeyLayout({}, ENERGY);
expect(data.nodes.length).toBe(48);
expect(data.links.length).toBe(68);

expect(data.nodes[0].name).toBe("Agricultural 'waste'");
expect(data.nodes[0].x).toEqual([0, 0.008, 0.008, 0]);
expect(data.nodes[0].y).toEqual([
0.15714829392583463,
0.15714829392583463,
0.17602864502202453,
0.17602864502202453,
]);

expect(data.links[0].source.name).toBe("Agricultural 'waste'");
expect(data.links[0].target.name).toBe('Bio-conversion');
expect(data.links[0].x).toEqual([0.008, 0.008, 0.1417142857142857, 0.1417142857142857]);
expect(data.links[0].y).toEqual([
0.17602864502202453,
0.15714829392583463,
0.23174113600532192,
0.21286078490913202,
]);
});
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"@antv/g2": "^4.1.0-beta.21",
"d3-hierarchy": "^2.0.0",
"d3-regression": "^1.3.5",
"d3-sankey": "^0.12.3",
"dayjs": "^1.8.36",
"size-sensor": "^1.0.1",
"tslib": "^1.13.0"
Expand Down
8 changes: 7 additions & 1 deletion src/plots/sankey/adaptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ function geometry(params: Params<SankeyOptions>): Params<SankeyOptions> {

chart.data(data);

chart.interval().position(`${sourceField}*${targetField}`).color(weightField);
// node view
const nodeView = chart.createView();
nodeView.data([]);

// edge view
const edgeView = chart.createView();
edgeView.data([]);

return params;
}
Expand Down
12 changes: 12 additions & 0 deletions src/plots/sankey/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ export class Sankey extends Plot<SankeyOptions> {
/** 图表类型 */
public type: string = 'sankey';

protected getDefaultOptions() {
return {
syncViewPadding: true,
nodeWidthRatio: 0.008,
nodePaddingRatio: 0.03,
tooltip: {
showTitle: false,
showMarkers: false,
},
};
}

/**
* 获取适配器
*/
Expand Down
48 changes: 41 additions & 7 deletions src/plots/sankey/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,45 @@
import { Options } from '../../types';
import { Data, Datum, Options, StyleAttr } from '../../types';

/** 配置类型定义 */
export interface SankeyOptions extends Omit<Options, 'xField' | 'yField' | 'xAxis' | 'yAxis'> {
/** 来源字段 */
readonly sourceField?: string;
/** 去向字段 */
readonly targetField?: string;
/** 权重字段 */
readonly weightField?: string;
/**
* 来源字段
*/
readonly sourceField: string;
/**
* 去向字段
*/
readonly targetField: string;
/**
* 权重字段
*/
readonly weightField: string;
/**
* 数据
*/
readonly data: Data;
/**
* 节点宽度的比如,参考画布的宽度,默认值为 0.008
*/
readonly nodeWidthRatio?: number;
/**
* 节点之间的间距比例,参考画布高度,默认值为 0.03
*/
readonly nodePaddingRatio?: number;
/**
* 节点对齐的方式,默认为 justify
*/
readonly nodeAlign?: 'left' | 'right' | 'center' | 'justify';
/**
* 节点排序方式,默认为空
*/
readonly nodeSort?: (a: Datum, b: Datum) => number;
/**
* 节点样式
*/
readonly nodeStyle?: StyleAttr;
/**
* 边样式
*/
readonly edgeStyle?: StyleAttr;
}
Loading

0 comments on commit fe7aaa1

Please sign in to comment.