What we want to solve
I want to separate the colors of the graph from 0 to plus or minus, but I have tried several galleries and looked at Issues, but I can't get the graph to render properly. I am very sorry, but I would appreciate your answer.
I tried using and also < Threshold > but could not complete it.
Assumed chart
Code
First, AreaClose was used. Never mind about color transparency and gradients.
import { LoginContentsWithSideBar } from "src/components/projects/LoginContentsWithSideBar"
import { mediaQueryTabletMaxWidth } from "src/constants/deviceDimensions"
import { COLORS } from "src/constants/colors"
import styled from "styled-components"
import { Card } from "src/components/projects/Manage/Assets/Card"
import { LinePath, AreaClosed } from "@visx/shape"
import { scaleTime, scaleLinear } from "@visx/scale"
import { AxisLeft, AxisBottom} from "@visx/axis"
import { Group } from "@visx/group"
import { GridRows, GridColumns } from "@visx/grid"
import dayjs from "dayjs"
import { curveBasis, curveMonotoneX } from '@visx/curve';
import { Threshold } from '@visx/threshold';
import { extent } from 'd3-array';
import { LinearGradient } from '@visx/gradient';
type Props = {
date: Date
value: number
}
type DatePoint = Props[]
const data: DatePoint = [
{ date: new Date("2023-01"), value: -10 },
{ date: new Date("2023-02"), value: -100 },
{ date: new Date("2023-03"), value: 105 },
{ date: new Date("2023-04"), value: 100 },
{ date: new Date("2023-05"), value: 100 },
{ date: new Date("2023-06"), value: 105 },
{ date: new Date("2023-07"), value: 100 },
{ date: new Date("2023-08"), value: 105 },
{ date: new Date("2023-09"), value: 100 },
{ date: new Date("2023-10"), value: 100 },
{ date: new Date("2023-11"), value: -105 },
{ date: new Date("2023-12"), value: -100 },
{ date: new Date("2024-01"), value: 105 },
{ date: new Date("2024-02"), value: -100 },
{ date: new Date("2024-03"), value: 105 },
{ date: new Date("2024-04"), value: 100 },
{ date: new Date("2024-05"), value: 100 },
{ date: new Date("2024-06"), value: 105 },
]
const formatDate = (date: unknown) => {
if (!(date instanceof Date)) {
return ""
}
return dayjs(date).format("YYYY/MM")
}
export const TestChart = () => {
const width = 1100
const height = 600
const margin = { top: 20, right: 20, bottom: 30, left: 50 }
const getDate = d => d.date;
const getValue = d => d.value;
const negativeData = data.filter( d => d.value <= 0)
const positiveData = data.filter( d => d.value >= 0)
const xMax = width - margin.left - margin.right
const yMax = height - margin.top - margin.bottom
// scales
const xScale = scaleTime({
domain: domain,
range: [margin.left, width - margin.right],
});
const yScale = scaleLinear({
domain: [Math.min(0, ...data.map(d => d.value)), Math.max(...data.map(d => d.value))],
range: [height - margin.bottom, margin.top],
});
return (
<svg width={width} height={height}>
<GridRows scale={profitScale} width={xMax} height={yMax} left={50} stroke="#4D4D4D" numTicks={10} />
<GridColumns scale={timeScale} width={1200} height={550} top={20} stroke="#4D4D4D" numTicks={15} />
<AreaClosed
data={positiveData}
yScale={yScale}
x={d => xScale(getDate(d))}
y={d => yScale(getValue(d))}
stroke="red"
fill="red"
/>
<AreaClosed
data={negativeData}
yScale={yScale}
x={d => xScale(getDate(d))}
y={d => yScale(getValue(d))}
stroke="blue"
fill="blue"
/>
<AxisLeft
scale={profitScale}
left={margin.left}
stroke="#4D4D4D"
hideTicks
tickLabelProps={() => ({
fill: COLORS.NEUTRAL100,
fontSize: 14,
textAnchor: "end",
dy: "0.2em",
dx: "-0.5em",
})}
/>
<AxisBottom
scale={timeScale}
top={height - margin.bottom}
tickFormat={formatDate}
stroke="#4D4D4D"
hideTicks
tickLabelProps={() => ({
fill: COLORS.NEUTRAL100,
textAnchor: "middle",
fontSize: 11,
dy: "0.2em",
})}
tickValues={data.map(d => d.date)}
/>
</svg>
)
}
Next we used Threshold I will only include the code for the changes.
const timeScale = scaleTime({
domain: [
new Date(Math.min(...data.map((d) => d.date.getTime()))),
new Date(Math.max(...data.map((d) => d.date.getTime()))),
],
range: [margin.left, width - margin.right],
})
const valueScale = scaleLinear({
domain: [Math.min(...data.map((d) => d.value)), Math.max(...data.map((d) => d.value))],
range: [height - margin.bottom, margin.top],
})
return(
・・・
<Threshold
id={"1"}
data={data}
x={d => timeScale(d.date)}
y0={d => valueScale(Math.min(0, d.value))}
y1={d => valueScale(Math.max(0, d.value))}
clipAboveTo={0}
clipBelowTo={yMax}
curve={curveBasis}
belowAreaProps={{
fill: 'blue',
fillOpacity: 0.4,
}}
aboveAreaProps={{
fill: 'red',
fillOpacity: 0.4,
}}
/>
)
What I tried
- Check the Issues
- Use of Threshod
- Use of AreaColose