🏠 back to Observable

Tiled bar chart in d3


I’m trying to build a tiled bar charts with d3, because I found out limitation with vega-lite and want to prioritize mastering d3js before vega.

I need help to position the bar charts inside each tile.

What I did:

  1. built the tiles here using simple d3.scaleBand

  2. generated a simple random bar chart here

  3. next, and this is where I’m stuck, I want to insert a generated bar chart inside a per-positioned tile current draft.

The aim will be to then associate to each tile to a different bar chart.

I think, I am stuck because I still don’t understand how to use d3.selection and join to zip all my tiles with the corresponding bar charts.

For example why can’t I do

test = {
  let container = d3.create('svg').attr('id', 'container-1');  // a selection

  let content = d3.create('rect').attr('id', 'content-1')
  .attr('x', 0)
  .attr('y', 0)
  .attr('width', 100)
  .attr('height', 50);  // another selection

  // why can't I add the node to the selection as so ?
  let res = container.append(content.node()); 

// or  let res = container.append(content)); 

  return res;  
 ** error ** 
test = InvalidCharacterError: Failed to execute 'createElementNS' on 'Document': The qualified name provided ('[object HTMLUnknownElement]') contains the invalid name-start character '['.

But this will work ?

test2 = { 
  let res = d3.create('svg').attr('id', 'container-1')  // the container

  .append('rect').attr('id', 'content-1')  // appending the content
  .attr('x', 0)
  .attr('y', 0)
  .attr('width', 100)
  .attr('height', 50);  

  return res;  // ok

What am I not understanding ?

note: I have been reading and rereading official d3-selection doc, for several years now, following its updates, but I don’t get it. I feel terribly stupid and start to believe that if I’m not sub-human then you, that master it, are super-human… sad for me :o(

This is getting closer but not yet perfect. and I don’t understand why d3.select(container) when container instanceof d3.selection is true

  let res = d3.select(container).select(
    function(d, i, nodes){
      return this.node().appendChild(content.node())

The tilded bar chart are not perfect but, I’m satisfied now –> see result.

The problem I was facing is not understanding correctly svg.
svg elements are not link html element. Not all svg elements can be containers for others.

In my case I needed to do two things to move forward:

  1. replace the tile svg:rect by svg:g or svg:svg (a svg container see spec.)
  2. Chain the selection g.selectAll("svg").data(tiles).join('g')
    with a select(function ...) as folow:
    .select((d, i, nodes)=>{


      return multiHisto[i].node();


Another thing with was not clear is the difference between the above notation and

    .select( function(d, i){


      return multiHisto[i].node();


I know recall that thethis argument cannot be used with ES6 syntax.