score:1

I clearly see your last timestamp goes back in time (02:28:00 -> 02:00:00)

808: {open: 28935.51, close: 29053.97, high: 29139.7, low: 28875.91, date: Thu May 13 2021 02:28:00}
809: {open: 28996.66, close: 28812.63, high: 29046.49, low: 28760.27, date: Thu May 13 2021 02:00:00}

The snippet demonstrates that removing the last item from the data fixes the problem:

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", d => linefunc(xScale, yScale, 9, d))
    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, d) => {
    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)(d.slice(0, -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>


Related Query

More Query from same tag