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