D3 Basics Visualiseren - marcoFijan/frontend-data GitHub Wiki

Ik vond D3 zelf erg verwarrend werken. Vooral de selectAll function vond ik erg verwarrend. Ik ben rustig de video's van Curran gaan volgen en ondertussen ben ik zelf mee gaan typen en heb ik een cheatsheet bijgehouden met belangrijke en handige informatie. Hier vindt u dan ook mijn uitleg over d3. Afgelopen donerdeag 5 november begon ik pas het licht te zien. Hieronder laat ik mijn kort mijn proces zien voor het leren van de basics van d3. Dit ging hand in hand met de basis video's van curran.

Nadat ik de RDWData had ingeladen, begon ik met een nieuwe function: createDiagram. In deze function wilde ik mijn d3 logica stoppen. Later ga ik deze function nog onderverdelen in kleinere functions zodat d3 ook op met functional patterns geschreven wordt.

Schalen toevoegen

Ik begon met de basics van scaleLinear() en scaleBand(). ScaleLinear vond ik vrij logisch. ScaleBand vond ik wel verwarrend.

Ik begon eerst heel simpel met alleen de vierkanten maken met een datajoin:

const createDiagram = data => {
  svg.selectAll('rect').data(data)
    .enter().append('rect')
      .attr('width', 300)
      .attr('height', 300)

Scales toevoegen:

const createDiagram = data => {
  const scaleX = d3.scaleLinear()
    .domain([0, d3.max(data, d => d.chargingpointcapacity)])
    .range([0, width])

  const scaleY = d3.scaleBand()
    .domain(data.map(d => d.areamanagerid))
    .range([0, height])

  svg.selectAll('rect').data(data)
    .enter().append('rect')
      .attr('y', d => scaleY(d.areamanagerid))
      .attr('width', d => scaleX(d.chargingpointcapacity))
      .attr('height', scaleY.bandwidth())
}

Axis callen

  const g = svg.append('g')
    .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')

  g.append('g').call(d3.axisLeft(scaleY))
  g.append('g').call(d3.axisBottom(scaleX))
    .attr('transform', 'translate(0,' + innerHeight + ')')

Dit ging nog makkelijk. Later liep ik wel vast door de call van de axisses. Maar dit komt later

Kaart draaien

Curran liet in zijn voorbeeld een kaart zien die vanaf de zijkant gemaakt werd. Hierdoor had hij het probleem niet dat bij d3 de staven in een staafdiagram vanaf linksbovenin gemaakt worden. Ik wilde dit proberen te draaien. Dit heeft mij heel veel tijd gekost. De staven kreeg ik makkelijk gedraaid door overal scaleY en scaleX te draaien.

  const scaleX = d3.scaleLinear()
    .domain([0, d3.max(data, valueX)])
    .range([0, innerWidth])
    console.log(data)
    console.log(scaleX.domain())

  const scaleY = d3.scaleBand()
    .domain(data.map(valueY))

werd

  const scaleY = d3.scaleLinear()
    .domain([0, d3.max(data, valueY)])
    .range([0, innerHeight])
    .nice()
    console.log(scaleY.range())
    console.log(scaleY.domain())

  const scaleX = d3.scaleBand()
    .domain(data.map(valueX))
    .range([0, innerWidth])

En het appenden van de vierkanten moesten ook veranderd worden

    .attr('y', d => scaleY(valueY(d)))
    .attr('width', d => scaleX(valueX(d)))
    .attr('height', scaleY.bandwidth())

werd

    .attr('x', d => scaleX(valueX(d)))
    .attr('y', d => scaleY(valueY(d)))
    .attr('height', d => scaleY(valueY(d)))
    .attr('width', scaleX.bandwidth())

Alleen nu waren de balken verkeerd om. Ze begonnen bovenaan. Ik wist de staven op te lossen door de attribute y te veranderen door de hoogte te pakken en daar de scaleY hoogte vanaf te halen:

    .attr('y', d => innerHeight - scaleY(valueY(d)))

Hierdoor waren de staven goed. Maar de y-as was nog steeds gedraaid. De y-as begon rechtsovenin met 0 en eindigde met 1800 waar de staven begonnen. Online vond ik dat je de domain van y moet omdraaien zodat de as begint bij het hoogste getal en aftelt naar 0:

    .domain([0, d3.max(data, valueY)])

naar

    .domain([d3.max(data, valueY), 0])

Maar hierdoor tripte mijn staven helemaal. Ik heb hier uren op lopen schreeuwen. Uiteindelijk kwam ik erachter dat mijn d3.max() niet goed werkt. Hij rekende de op 1 na hoogste capacity uit in plaats van de hoogste. Wat bleek, ondanks dat console.log(scaleY.domain) wel een integer terug gaf, waren de values geen integers maar strings! Door dit aan te passen had ik eindelijk normale staven met een correcte y-as

  const valueY = d => d.capacity = +d.capacity

Ticks

Vervolgens wilde ik aan de slag gaan met de ticks. Maar, ook hier had ik problemen. Ik had precies dezelfde code van Curran en andere voorbeelden op het internet, maar toch wilde bij mij de ticks niet verdwijnen. Ook langer maken had geen effect. Uiteindelijk bleek het te komen door de call. Het is belangrijk om de call pas als laatst uit te voeren. Eerst maak je de aanpassingen aan de assen, dan voer je de call uit.

// first the edit
  const yAxis = d3.axisLeft(scaleY)
    .tickSize(-innerWidth)

  const xAxis = d3.axisBottom(scaleX)

// then the call
  const yAxisGroup = g.append('g').call(d3.axisLeft(scaleY))
  const yAxisGroup = g.append('g').call(yAxis)
  yAxisGroup.select('.domain').remove()

That's it! Nu had ik een werkende staafdiagram met de gefilterde RDWData. afbeelding.png