# D3

The basis of D3 is that we select and manipulate DOM elements based on data.

# Basic setup

<body>
  <script>
    const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9]

    d3.select('body')
      .selectAll('h2')
      .data(dataset)
      .enter()
      .append('h2')
      .text((d) => d + ' USD')
      .style('color', (d) => {
        return d < 20 ? 'red' : 'green'
      })

    // Add your code above this line
  </script>
</body>
<body>
  <script>
    const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];

    const w = 500;
    const h = 100;

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

    svg.selectAll("rect")
       .data(dataset)
       .enter()
       .append("rect")
       .attr("x", (d, i) => i * 30)
       .attr("y", (d, i) => h - 3 * d)
       .attr("width", 25)
       .attr("height", (d, i) => d * 3)
       .attr("fill", "navy");

    svg.selectAll("text")
       .data(dataset)
       .enter()
       .append("text")
       .text((d) => d)
       .attr("x", (d, i) => i * 30)
       .attr("y", (d, i) => h - (3 * d) - 3)
  </script>
</body>

# Using SVG

  • We use SVGs because they are scalable (Scalable Vector Graphics).
  • We will set width & height of the SVG unitless, meaning only ratio. For example const w=500 and const h=300.
  • attr('height', h)
  • SVG elements like rect and g will be ur building blocks.
  • With a rect inside an SVG, x and y will determine its placement.

# D3 methods

A common workflow pattern is to create a new element in the document for each piece of data in the set. D3 has the enter() method for this purpose.

When enter() is combined with the data() method, it looks at the selected elements from the page and compares them to the number of data items in the set. If there are fewer elements than data items, it creates the missing elements.

  • select(), append(), selecteAll().
  • The attr() method in D3 accepts a callback function to dynamically set that attribute. The callback function takes two arguments, one for the data point itself (usually d) and one for the index of the data point in the array. The second argument for the index is optional. selection.attr("property", (d, i) => {})
  • To invert a bar char we need to fiddle with the y. Usually: y = h - m * d, where m is the constant that scales the data points.
  • Position and size are .attr, and all other decoration is .style.
  • Range of the dataset = domain. We will use the .scale() to set a scale. There is also scale.domain(), scale.range(). Domain covers the input values, while range covers the output values (our SVG size for example).
  • We can use d3.min() and d3.max() to determine the max and min points of our dataset so we can set our scale. These methods take a callback, so if we had nested arrays in our data, we could point them to the correct one, like (d) => d[1].
  • Example of setting a scale and adding padding:
const padding = 30
const xScale = d3
  .scaleLinear()
  .domain([0, d3.max(dataset, (d) => d[0])])
  .range([padding, w - padding])
  • Always be wary about upside down things, think graphics.
  • To render the axes: axisLeft() and axisBottom().