D3 library not converting value properly (React Native)

Viewed 34

I have a bar graph that displays a duration of time, however, the bars are not displaying accurately. For example: The total duration is 1h 05m, which equals the value of 1.0757. When I call the d3 function on the total duration: d3.scaleLinear().range([0,height]).domain([min,max]), it returns a value of 31.8486, making the bar graph line look like it is depicting 30 minutes vs over an hour.

What needs to be switched to make sure the bar graph displays the data correctly?

let h = 200;
let y = this.getDomainAndRange(data, h);

let displayOrder = [
  0: {dayName: "Sunday", totalDuration: {value: 2.6707, display: "2h 40m"},
  1: {dayName: "Monday", totalDuration: {value: 1.0757, display: "1h 5m"},
  2: {dayName: "Tuesday", totalDuration: {value: 1.562, display: "1h 34m"}
]
// Once d3 is called on the totalDuration[value], it returns:
// 0: 200 (appears on the screen as 3h), 
// 1: 31.8486 (appears on the screen as 30m),
// 2: 83.116335 (appears on the screen as 1h 10m)

<Svg>
displayOrder.map((wd, idx) => {
   let barHeight = this.getDayDurationHeight(data, wd, y);
   let actualDuration = this.getActualDuration(data, wd)
   return (
    <G key={data["start"] + "g_" + idx}>
      <Rect key={data["start"] + "wdb_" + idx} id={actualDuration} x={(idx + 1) * 45} width={bw} y={h - barHeight} height={barHeight} fill={purple} />
    </G>
   );
})
</Svg>
getDomainAndRange(data, height) {
 //iterate through each day and find the min and max value...
 let days = data["days"];
 let min = Number.MAX_SAFE_INTEGER;
 let max = Number.MIN_SAFE_INTEGER;
 for (let i = 0; i < days.length; i++) {
   let day = days[i];
   if (day["totalDuration"]["value"] > max) max = day["totalDuration"]["value"];
   if (day["totalDuration"]["value"] < min) min = day["totalDuration"]["value"];
 }
 if (max <= 0) max = 1;
 let x = d3.scaleLinear().range([0, height]).domain([min, max])
 return x;
}

getDayDurationHeight(data, dayName, dr) {
 //iterate through each day and find the bar height value...
 let days = data["days"];
 let duration = dr(0);

 for (let i = 0; i < days.length; i++) {
   let day = days[i];
   if (day["dayName"] == dayName) {
    //this is where the d3 function is converting the value
    duration = dr(day["totalDuration"]["value"]);
   }
 }
 return duration;
}

getActualDuration(data, dayName){
  let days = data["days"];
  let duration = 0

  for (let i = 0; i < days.length; i++) {
    let day = days[i];
    if (day["dayName"] == dayName) {
      duration = (day["totalDuration"]["display"]);
    }
  }
  return duration;
}
1 Answers

Here is the solution:

if (day["totalDuration"]["value"] > max) max = day["totalDuration"]["value"];

needs to be switched to

if (day["totalDuration"]["value"] > max) max = Math.ceil(day["totalDuration"]["value"]);

Also, min in the d3 function needs to be set to 0.

original: let x = d3.scaleLinear().range([0, height]).domain([min, max])

fixed: let x = d3.scaleLinear().range([0, height]).domain([0, max])

The reason: the top line is being set to max, which currently is the exact number of the line. Adding Math.ceil() switches the top line to be a whole number. Also, the bottom line was rising to the min. Instead, it should always be 0 and not switch according to min.

Related