I drew a line chart with d3 using generated data.
The line you see below represents an average of 9 minutes.
The line does inverts at the end of the chart, and reverses back onto itself, then stops around the middle of the chart. My problem is that the line should not wrap back onto itself at the end, and I do not know why it is doing that.
I can see that the data from 2021-5-13-02-00 is causing the inversion, however, data from 2021-5-13-02-00 does not exist in end of the generated CSV file data.
I need to find out where this data, that I am not inputting, is coming from.
Any help fixing this would be great, thank you!
The picture: chart direction is inverted at last of a few

margin = {top: 0, bottom: 20, left: 40, right: 20}
function apply_attrs(selection, attrs_func, xScale, yScale) {
const s = attrs_func(selection, xScale, yScale)
return s
}
function path_9_attr_func(selection, xScale, yScale) {
selection
.attr("fill", "none")
.attr("stroke", "#00ff00")
.attr("d", linefunc(xScale, yScale, 9))
return selection
}
function max_in_obj(data, property_name) {
const high = data.reduce((acc, cur, ind) => {
if (cur[property_name] > acc) {
acc = cur[property_name]
}
return acc
}, data[0][property_name])
return high
}
function min_in_obj(data, property_name) {
const low = data.reduce((acc, cur, ind) => {
if (cur[property_name] < acc) {
acc = cur[property_name]
}
return acc
}, data[0][property_name])
return low
}
const linefunc = (xScale, yScale, n) => {
return d3.line()
.x((d, i, data) => {
if (isNaN(d.date)) {
return 0
}
let retval = xScale(d.date)
if (d.date.getMinutes() === 30) {
console.log("Here is 30", d, i)
}
return retval
})
.y((d, i, data) => {
let sliced;
sliced = data.slice(i-(n-1), i+1);
const val = (min_in_obj(sliced, "low") + max_in_obj(sliced, "high")) / 2
return yScale(val)
}).defined((d, i, data) => i >= n-1)
}
const f = async () => {
let num = 0
let res = await fetch("https://gist.githubusercontent.com/KiYugadgeter/a8527ff1d9aa12f68b9d48d6fc09496a/raw/4bd019b8c6d6e2be2ecfd7180a64a6356fc34f11/stack_overflow_why_invert.csv")
let d = await res.text()
let min_value = 999999999
let max_value = 0
data = parsed_data = d3.csvParse(d, (dt) => {
const j = dt.date.split("-").map((i) => {
const p = parseInt(i)
return p
})
const date = new Date(j[0], j[1]-1, j[2], j[3], j[4], 0)
//num++
console.log(date, j[4], dt)
high_value = parseFloat(dt.high)
low_value = parseFloat(dt.low)
open_value = parseFloat(dt.open)
close_value = parseFloat(dt.close)
if (low_value < min_value) {
min_value = low_value
}
if (high_value > max_value) {
max_value = high_value
}
return {
open: open_value,
close: close_value,
high: high_value,
low: low_value,
date: date
}
})
return {data: data, min: min_value, max: max_value}
}
f().then((d) => {
let num = 0
let recently_date = d.data[d.data.length-1].date
let minvalue = 99999999999
let maxvalue = 0
recently_date.setMinutes(recently_date.getMinutes() - (recently_date.getMinutes() % 30))
recently_date.setSeconds(0)
recently_date.setMilliseconds(0)
recently_date = new Date(recently_date.getTime() + 30 * 60000)
const limit_date = (recently_date - (60 * 90 * 1000))
let data = d.data.filter((d) => {
num++
if (d.low < minvalue) {
minvalue = d.low
}
if (d.high > maxvalue) {
maxvalue = d.high
}
return true
})
const svg = d3.select("svg")
const xScale = d3.scaleTime().domain(
[
limit_date,
recently_date
]
).nice().range([margin.left, 600-margin.left-margin.right])
const yScale = d3.scaleLinear().domain([(maxvalue - (maxvalue%1000) + 2000), (minvalue - (minvalue%1000) - 2000)]).range([0, 410-margin.top-margin.bottom])
const canvas = svg.append("g").attr("width", 600).attr("height", 410)
const clip = svg.append("clipPath").attr("id", "clip").append("rect").attr("width", 600-margin.left-margin.right).attr("height", 410-margin.bottom-margin.top).attr("x", margin.left).attr("y", 0)
const candles_layer = canvas // Data group
.append("g")
.attr("stroke-linecap", "square")
.attr("stroke", "black")
.attr("clip-path", "url(#clip)")
const path_9min = canvas
.append("path")
const path_9_selection = path_9min
.attr("clip-path", "url(#clip)")
.datum(data)
apply_attrs(path_9_selection, path_9_attr_func, xScale, yScale)
const xaxis = d3.axisBottom(xScale).ticks().tickFormat(d3.timeFormat("%H:%M"))
const group_x = canvas
.append("g")
.attr("transform", "translate(0," + String(410-margin.top - margin.bottom) + ")") // X axis
.call(xaxis).style("font-size", "5")
const yaxis = d3.axisLeft(yScale)
const group_y = canvas
.append("g")
.attr("class", "axis axis--y")
.attr("transform", "translate(" + String(margin.left) + ",0)") // Y axis
.call(yaxis)
.style("font-size", "5")
})
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v6.min.js"></script>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="index.css">
</head>
<body>
<svg id="svg" viewBox="0 0 600 410">
</svg>
</body>
</html>