-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
384 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { useSpring, animated } from "@react-spring/web"; | ||
import styles from "./streamgraph.module.css"; | ||
|
||
type AnimatedPathItemProps = { | ||
path: string; | ||
color: string; | ||
}; | ||
|
||
export const AnimatedPathItem = ({ path, color }: AnimatedPathItemProps) => { | ||
const springProps = useSpring({ | ||
to: { | ||
path, | ||
}, | ||
config: { | ||
friction: 100, | ||
}, | ||
immediate: true, | ||
}); | ||
|
||
return ( | ||
<animated.path | ||
className={styles.shape} | ||
d={springProps.path} | ||
opacity={1} | ||
stroke="grey" | ||
fill={color} | ||
fillOpacity={0.8} | ||
cursor="pointer" | ||
/> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import * as d3 from "d3"; | ||
import styles from "./streamgraph.module.css"; | ||
import { AnimatedPathItem } from "./AnimatedPath"; | ||
|
||
const MARGIN = { top: 30, right: 30, bottom: 50, left: 50 }; | ||
|
||
const OFFSET_TYPES = { | ||
silouhette: d3.stackOffsetSilhouette, | ||
wiggle: d3.stackOffsetWiggle, | ||
none: d3.stackOffsetNone, | ||
diverging: d3.stackOffsetDiverging, | ||
expand: d3.stackOffsetExpand, | ||
}; | ||
|
||
const CURVE_TYPES = { | ||
curveBasis: d3.curveBasis, | ||
bumpX: d3.curveBumpX, | ||
bumpY: d3.curveBumpY, | ||
curveCardinal: d3.curveCardinal, | ||
catMullRom: d3.curveCatmullRom, | ||
curveLinear: d3.curveLinear, | ||
curveNatural: d3.curveNatural, | ||
curveStep: d3.curveStep, | ||
}; | ||
|
||
type StreamGraphProps = { | ||
width: number; | ||
height: number; | ||
data: { [key: string]: number }[]; | ||
offsetType: string; | ||
curveType: string; | ||
}; | ||
|
||
export const StreamGraph = ({ | ||
width, | ||
height, | ||
data, | ||
offsetType, | ||
curveType, | ||
}: StreamGraphProps) => { | ||
// bounds = area inside the graph axis = calculated by substracting the margins | ||
const boundsWidth = width - MARGIN.right - MARGIN.left; | ||
const boundsHeight = height - MARGIN.top - MARGIN.bottom; | ||
|
||
const groups = ["groupA", "groupB", "groupC", "groupD"]; | ||
|
||
// Data Wrangling: stack the data | ||
const stackSeries = d3 | ||
.stack() | ||
.keys(groups) | ||
.order(d3.stackOrderNone) | ||
.offset(OFFSET_TYPES[offsetType]); | ||
const series = stackSeries(data); | ||
|
||
// Y axis | ||
const topYValues = series.flatMap((s) => s.map((d) => d[1])); // Extract the upper values of each data point in the stacked series | ||
const yMax = Math.max(...topYValues); | ||
|
||
const bottomYValues = series.flatMap((s) => s.map((d) => d[0])); // Extract the upper values of each data point in the stacked series | ||
const yMin = Math.min(...bottomYValues); | ||
|
||
const yScale = d3.scaleLinear().domain([yMin, yMax]).range([boundsHeight, 0]); | ||
|
||
// X axis | ||
const [xMin, xMax] = d3.extent(data, (d) => d.x); | ||
const xScale = d3 | ||
.scaleLinear() | ||
.domain([xMin || 0, xMax || 0]) | ||
.range([0, boundsWidth]); | ||
|
||
// Color | ||
const colorScale = d3 | ||
.scaleOrdinal<string>() | ||
.domain(groups) | ||
.range(["#e0ac2b", "#e85252", "#6689c6", "#9a6fb0", "#a53253"]); | ||
|
||
// Build the shapes | ||
const areaBuilder = d3 | ||
.area<any>() | ||
.x((d) => { | ||
return xScale(d.data.x); | ||
}) | ||
.y1((d) => yScale(d[1])) | ||
.y0((d) => yScale(d[0])) | ||
.curve(CURVE_TYPES[curveType]); | ||
|
||
const allPath = series.map((serie, i) => { | ||
const path = areaBuilder(serie); | ||
if (!path) { | ||
console.log("null"); | ||
return null; | ||
} | ||
return ( | ||
<AnimatedPathItem key={i} path={path} color={colorScale(serie.key)} /> | ||
); | ||
}); | ||
|
||
console.log({ allPath }); | ||
|
||
const grid = xScale.ticks(5).map((value, i) => ( | ||
<g key={i}> | ||
<line | ||
x1={xScale(value)} | ||
x2={xScale(value)} | ||
y1={0} | ||
y2={boundsHeight} | ||
stroke="#808080" | ||
opacity={0.2} | ||
/> | ||
<text | ||
x={xScale(value)} | ||
y={boundsHeight + 10} | ||
textAnchor="middle" | ||
alignmentBaseline="central" | ||
fontSize={9} | ||
stroke="#808080" | ||
opacity={0.8} | ||
> | ||
{value} | ||
</text> | ||
</g> | ||
)); | ||
|
||
return ( | ||
<div> | ||
<svg width={width} height={height}> | ||
<g | ||
width={boundsWidth} | ||
height={boundsHeight} | ||
transform={`translate(${[MARGIN.left, MARGIN.top].join(",")})`} | ||
> | ||
{grid} | ||
<g className={styles.container}>{allPath}</g> | ||
</g> | ||
</svg> | ||
</div> | ||
); | ||
}; |
64 changes: 64 additions & 0 deletions
64
viz/StreamGraphShapeTransition/StreamGraphShapeTransition.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { useState } from "react"; | ||
import { StreamGraph } from "./StreamGraph"; | ||
import { data } from "./data"; | ||
|
||
const BUTTON_HEIGHT = 50; | ||
|
||
export const StreamGraphShapeTransition = ({ width = 700, height = 400 }) => { | ||
const [offsetType, setOffsetType] = useState("silhouette"); | ||
const [curveType, setCurveType] = useState("curveLinear"); | ||
|
||
return ( | ||
<div> | ||
<div | ||
style={{ | ||
height: BUTTON_HEIGHT, | ||
display: "flex", | ||
marginTop: 20, | ||
alignItems: "center", | ||
}} | ||
> | ||
<span style={{ fontSize: 14, marginRight: 5 }}>Offset type</span> | ||
<select | ||
onChange={(e) => { | ||
setOffsetType(e.target.value); | ||
}} | ||
value={offsetType} | ||
style={{ fontSize: 14 }} | ||
> | ||
<option value="silouhette">Silouhette</option> | ||
<option value="none">None</option> | ||
<option value="wiggle">Wiggle</option> | ||
<option value="diverging">Diverging</option> | ||
<option value="expand">Expand</option> | ||
</select> | ||
<span style={{ fontSize: 14, marginRight: 5, marginLeft: 35 }}> | ||
Curve type | ||
</span> | ||
<select | ||
onChange={(e) => { | ||
setCurveType(e.target.value); | ||
}} | ||
value={curveType} | ||
style={{ fontSize: 14 }} | ||
> | ||
<option value="curveBasis">Cubic basis spline</option> | ||
<option value="bumpX">Bezier Curve Horizontal</option> | ||
<option value="bumpY">Bezier Curve Vertical</option> | ||
<option value="curveCardinal">Cubic cardinal spline </option> | ||
<option value="catMullRom">Catmull–Rom spline</option> | ||
<option value="curveLinear">Polyline</option> | ||
<option value="curveNatural">Natural cubic spline</option> | ||
<option value="curveStep">Step function</option> | ||
</select> | ||
</div> | ||
<StreamGraph | ||
data={data} | ||
width={width} | ||
height={height - BUTTON_HEIGHT} | ||
offsetType={offsetType} | ||
curveType={curveType} | ||
/> | ||
</div> | ||
); | ||
}; |
6 changes: 6 additions & 0 deletions
6
viz/StreamGraphShapeTransition/StreamGraphShapeTransitionDemo.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { StreamGraphShapeTransition } from "./StreamGraphShapeTransition"; | ||
|
||
export const StreamGraphShapeTransitionDemo = ({ | ||
width = 700, | ||
height = 400, | ||
}) => <StreamGraphShapeTransition width={width} height={height} />; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
export const data = [ | ||
{ | ||
x: 1, | ||
groupA: 38, | ||
groupB: 19, | ||
groupC: 9, | ||
groupD: 4, | ||
}, | ||
{ | ||
x: 2, | ||
groupA: 16, | ||
groupB: 14, | ||
groupC: 96, | ||
groupD: 40, | ||
}, | ||
{ | ||
x: 3, | ||
groupA: 164, | ||
groupB: 96, | ||
groupC: 64, | ||
groupD: 40, | ||
}, | ||
{ | ||
x: 4, | ||
groupA: 32, | ||
groupB: 65, | ||
groupC: 64, | ||
groupD: 40, | ||
}, | ||
{ | ||
x: 5, | ||
groupA: 12, | ||
groupB: 80, | ||
groupC: 14, | ||
groupD: 10, | ||
}, | ||
{ | ||
x: 6, | ||
groupA: 12, | ||
groupB: 180, | ||
groupC: 14, | ||
groupD: 10, | ||
}, | ||
{ | ||
x: 7, | ||
groupA: 12, | ||
groupB: 70, | ||
groupC: 14, | ||
groupD: 10, | ||
}, | ||
{ | ||
x: 8, | ||
groupA: 12, | ||
groupB: 30, | ||
groupC: 24, | ||
groupD: 10, | ||
}, | ||
{ | ||
x: 9, | ||
groupA: 190, | ||
groupB: 18, | ||
groupC: 34, | ||
groupD: 10, | ||
}, | ||
{ | ||
x: 10, | ||
groupA: 10, | ||
groupB: 18, | ||
groupC: 4, | ||
groupD: 10, | ||
}, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import ReactDOM from "react-dom"; | ||
import { data } from "./data"; | ||
import { StreamGraph } from "./StreamGraph"; | ||
|
||
const rootElement = document.getElementById("root"); | ||
ReactDOM.render( | ||
<StreamGraph data={data} width={400} height={400} />, | ||
rootElement | ||
); |
Oops, something went wrong.