score:1

Accepted answer

the standard way to do this is by adding .attr("y", d => innerheight - yscale(d.ratio)) to your rects. you can adapt this to make sure that the height is always positive, and then position the bars accordingly.

// 1. her velger jeg body elementet og appender et svg element hvor vår figur skal plasseres
const height = 300
const width = 700
const margin = {
  top: 20,
  right: 20,
  bottom: 20,
  left: 30
}
const innerwidth = width - margin.left - margin.right
const innerheight = height - margin.top - margin.bottom

const svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height)

const render = data => {
  const yscale = d3.scalelinear()
    .domain([-5, 5])
    .range([innerheight, 0]);

  const xscale = d3.scaleband()
    .domain(data.map(d => d.run))
    .range([0, innerwidth])
    .padding(0.1)

  const yaxis = d3.axisleft(yscale)
  const xaxis = d3.axistop(xscale)

  const g = svg.append("g")
    .attr("transform", `translate(${margin.left},${margin.top})`)

  g.selectall("rect")
    .data(data)
    .enter()
    .append("rect")
    .attr('v', d => d.ratio)
    .attr("x", d => xscale(d.run))
    .attr("width", xscale.bandwidth())
    .attr("height", d => d.ratio < 0 ? yscale(d.ratio) - yscale(0) : yscale(0) - yscale(d.ratio))
    .attr("y", d => d.ratio < 0 ? yscale(0) : yscale(d.ratio))
    .attr("fill", d => d.ratio < 0 ? 'red' : 'green')

  yaxis(g.append("g"))
  xaxis(g.append("g").attr("transform", `translate(0,${yscale(0)})`))
}

const data = d3.range(14).map(i => ({
  ratio: -1 + math.random() * 2,
  run: i
}));
render(data);
<script src="https://d3js.org/d3.v6.min.js"></script>


Related Query

More Query from same tag