D3js Worshop

by @jecaestevez

Agenda

  • Do you know HTML
  • D3JS Basic usage
  • D3JS Working with Data
  • D3JS Advance
  • Resources

Do you know HTML?

 

  • Css
    • Selectors

Let's play in a online editor CodePen

<svg><svg/>

  • Line (stroke,x1,x2,y1,y2)
  • Rect(fill,x,y,width,height)
  • Circle (fill,cx,cy,r)

Absolute positioning; the origin ⟨0,0⟩ is the top-left corner!

HTML Basics

let's try apply simple colors

Css

Cascade Style Sheet is a declarative language for assigning styles to elements.

 

CSS assigns style rules via selectors.

 

Simple selectors identify elements by one facet

 

	            // element with ID myId
#myId               // <any id="myId">

                    // all DIV tags 
div                 // <div>
foo                 // <foo>

                    //  all elements with CLASS “box”
.myClass            // <any class="myClass">

[name=customName]   // <any name="customName">
[foo=bar]           // <any foo="bar">

		    // all SPAN tags inside DIVs
div span     	    // <div><span/></div>
foo bar             // <foo><bar/></foo>

		    //all DIV tags and all SPAN tags
div, span           // <div/><span/><div><span/><div>
foo, bar            //  <foo/><bar/><foo><bar/><foo>

		    //all div tags with CLASS "myClass"
div.myClass         // <div class="myClass">
foo.bar             // <foo class="bar">

		    //idiv tag with ID myId
div#myId            // <div id="myId">
foo#bar             // <foo id="bar">


		    //<span> with parent <div>
div > span 	    //<div><span/><div>

Css refactor

  1. Remove inline stroke.
  2. Add the following properties
    1. svg id="myId"
    2. line name="customName"
    3. rect class="myClass"
  3. Apply css styles to have the same than in the image

old style query selector

Open browser console run:

document.querySelectorAll("#myId")

 

	            // element with ID myId
#myId               // <any id="myId">

                    // all DIV tags 
div                 // <div>
foo                 // <foo>

                    //  all elements with CLASS “box”
.myClass            // <any class="myClass">

[name=customName]   // <any name="customName">
[foo=bar]           // <any foo="bar">

		    // all SPAN tags inside DIVs
div span     	    // <div><span/></div>
foo bar             // <foo><bar/></foo>

		    //all DIV tags and all SPAN tags
div, span           // <div/><span/><div><span/><div>
foo, bar            //  <foo/><bar/><foo><bar/><foo>

		    //all div tags with CLASS "myClass"
div.myClass         // <div class="myClass">
foo.bar             // <foo class="bar">

		    //idiv tag with ID myId
div#myId            // <div id="myId">
foo#bar             // <foo id="bar">


		    //<span> with parent <div>
div > span 	    //<div><span/><div>

Not familiar with cs and selector?

D3JS basic usage

  • Style
  • Attr
  • Classed
  • Selectors
  • Add/Remove
  • Text

Let's play in a online editor CodePen

https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js

Selectors

Returns the element found

d3.select('#myId')

Returns all found elements

d3.selectAll('.myClass')

	            // element with ID myId
#myId               // <any id="myId">

                    // all DIV tags 
div                 // <div>
foo                 // <foo>

                    //  all elements with CLASS “box”
.myClass            // <any class="myClass">

[name='customName']   // <any name="customName">
[foo=bar]           // <any foo="bar">

		    // all SPAN tags inside DIVs
div span     	    // <div><span/></div>
foo bar             // <foo><bar/></foo>

		    //all DIV tags and all SPAN tags
div, span           // <div/><span/><div><span/><div>
foo, bar            //  <foo/><bar/><foo><bar/><foo>

		    //all div tags with CLASS "myClass"
div.myClass         // <div class="myClass">
foo.bar             // <foo class="bar">

		    //idiv tag with ID myId
div#myId            // <div id="myId">
foo#bar             // <foo id="bar">


		    //<span> with parent <div>
div > span 	    //<div><span/><div>

Let's practice Selecting and show in console:

  1. body
  2. svg
  3. line
  4. circle
  5. rect

Add

// select the <body> element
var body = d3.select("body");

// add an <h1> element
var h1 = myBody.append("h1");
h1.text("H1 append to the body!"); 
// select all <section> elements
var allDivs= d3.selectAll("div");

// add an <h1> element to each
var h1 = allDivs.append("h1");
h1.text("Hello!");

many elements selected, adds one element to each.

one element selected, adds one element

Remove

// select the <body> element
var body = d3.select("h1");

// remove an <h1> element
var h1 = body.remove("h1");
// select all <section> elements
var allDivs= d3.selectAll("div");

// Remove All <div> element to each
var h1 = section.remove("h1");

many elements selected, remove one element to each.

one element selected, remove one element

From this 

add/remove

To do this

D3Js

 

  • Style
  • Attr
  • Classed
d3.select("p")
  .style("color","red");

d3.select("div")
  .classed("myClass",true);

d3.select("h1")
  .attr("title","my description");

D3Js

  • Style
  • Attr
  • Classed

From this using

To do this

D3Js working with Data

 

  • Dynamic Data
    • ​Enter/Update/Exit
  • Scale Domain Range

D3JS: data

  • How to add many elements
    • Data are arrays
      • Data are number
      • Data are objects
         
  • Use data to create multiple elements
     
  • Data is Asyncronus

D3js ENTER event

Data Array

.Enter( )

Elements Rendered

D3JS: data.enter() div

  • Appending to the enter selection creates the missing elements.The append method on enter selecti
  • The append method on enter selections is special; it still creates one new element per selected element, but it adds them to the parent node (here the SVG element).
var dataset=  [5,15,40,20];

d3.select("body")
  .selectAll('div')
	.data(dataset)
	.enter()
	.append("div")
	  .text(function(data,i){return data});

5

15

40

20

<body>




</body>
var dataset=  [5,15,40,20];

d3.select("body");
<body>
<!--
    <div></div>
    <div></div>
    <div></div>
    <div></div>
-->
</body>
<body>

<!-- 
     empty 
     selection
 -->

</body>
var dataset=  [5,15,40,20];

d3.select("body")
  .selectAll('div');
var dataset=  [5,15,40,20];

d3.select("body")
  .selectAll('div')
	.data(dataset);
var dataset=  [5,15,40,20];

d3.select("body")
  .selectAll('div')
	.data(dataset)
	.enter();
var dataset=  [5,15,40,20];

d3.select("body")
  .selectAll('div')
	.data(dataset)
	.enter()
	.append("div");
<body>
    <div>5</div>
    <div>15</div>
    <div>40</div>
    <div>20</div>
</body>
<body>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</body>

D3JS: data.enter() svg

mySvg.selectAll("text")
      .data(dataset)
      .enter()
      .append("text")
      .text((d) => d);
var dataset=  [5,15,40,20];

var mySvg = d3.select("svg");
mySvg.selectAll("text")
      .data(dataset)
      .enter()
      .append("text")
      .text((d) => d)
      .attr("y", 40)
    ;
mySvg.selectAll("text")
      .data(dataset)
      .enter()
      .append("text")
      .text((d) => d)
      .attr("x",(d,i) =>i*100)
      .attr("y", 40)
    ;
<html>
<body>
<svg></svg>
</body>
</html>
svg{
  width:500px;
  height:100px;
   border: 1px solid black;
}

TO DO THIS                               Started point : bit.ly/d3jsBlankSvg

D3JS: data.enter() svg

mySvg.selectAll("text")
      .data(dataset)
      .enter()
      .append("text")
      .text((d) => d)
      .attr("fill", "red")
      .attr("x",(d,i) =>i*100 +50)
      .attr("y", 40)
    ;
 
  mySvg.selectAll('circle')
	.data(dataset)
	.enter()
	.append("circle")
    .attr("cx",(d,i) =>i*100 +50)
    .attr("cy", 40)
    .attr("r", (d) =>d)
;

var dataset=  [5,15,40,20];

var mySvg = d3.select("svg");

started point                           to do                 this

D3js UPDATE event

Data Array

Update

Elements Rendered

D3JS: data.update()

​Solution with circles:
bit.ly/d3jsDataUpdateTextCircleSvg

mySvg.selectAll("text")
      .data(dataset)
      .enter()
      .append("text")
      .text((d) => d)
      .attr("x",(d,i) =>i*100)
      .attr("y", 40)
    ;
var dataset=  [5,15,40,20];

var mySvg = d3.select("svg");
function update(){
 dataset = [40,20,10,50];
  
  //Update Data - NOT using Enter()
  mySvg.selectAll("text")
      .data(dataset)
      .text((d) => d)
      .attr("x",(d,i) =>i*100)
      .attr("y", 40)
    ;
}
  <button onclick="update();">Update</button>

Trigger

Update

Data

D3js EXIT event

Data Array

.EXIT( )

Elements Rendered

D3JS: data.exit()

Solution with Circle:

bit.ly/d3jsDataExitTextCircleSvg

mySvg.selectAll("text")
      .data(dataset)
      .enter()
      .append("text")
      .text((d) => d)
      .attr("fill", "red")
      .attr("x",(d,i) =>i*100 +50)
      .attr("y", 40)
    ;
var dataset=  [5,15,40,20];

var mySvg = d3.select("svg");
function exit(){
     dataset =[];
 dataset = [5,15,40];
  
  //Update Data
  mySvg.selectAll("text")
      .data(dataset)
      .exit()
      .remove()
    ;
}
  <button onclick="exit();">Delete</button>

Remove

value

"20"

D3js Enter - Update - Exit

Data Array

Update

Elements Rendered

.EXIT( )

.ENTER( )

D3JS: data objects!

var dataset=   [
  {name: "Daniel", score: 5, colour:"red"},
  {name:   "Fer", score:  15, colour:"orange"},
  {name: "Marc", score: 40, colour:"black"},
  {name: "Enric", score: 20, colour:"blue"}
];
var mySvg = d3.select("svg");
mySvg.selectAll("text")
      .data(dataset)
      .enter()
      .append("text")
      .text((d) =>d.score)
      .attr("fill", (d)=>d.colour)
      .attr("x",(d,i) =>i*100)
      .attr("y", 40)
    ;
mySvg.selectAll("text")
      .data(dataset)
      .enter()
      .append("text")
      .text((d) => d)
      .attr("fill", "red")
      .attr("x",(d,i) =>i*100)
      .attr("y", 40)
    ;

 

Started point                 to do                   this
bit.ly/d3jsStartedPoint2

D3JS: be functional

var dataset=   [
  {name: "Daniel", score: 5, colour:"red"},
  {name:   "Fer", score:  15, colour:"orange"},
  {name: "Marc", score: 40, colour:"balck"},
  {name: "Enric", score: 20, colour:"blue"}
];
var mySvg = d3.select("svg");
function getScore(d,i) { return i * 100; }
function getColour(d) {  return d.colour; }
mySvg.selectAll("text")
      .data(dataset)
      .enter()
      .append("text")
      .text((d) => getScore(d))
      .attr("fill", (d)=>getColour(d))
      .attr("x",(d,i) =>getScore(d,i) )
      .attr("y", 40)
    ;

Instead to bind to values use functions

mySvg.selectAll("text")
      .data(dataset)
      .enter()
      .append("text")
      .text((d) =>d.score)
      .attr("fill", (d)=>d.colour)
      .attr("x",(d,i) =>i*100)
      .attr("y", 40)
    ;

Use functions instead to use directly the values
started point

bit.ly/d3jsDataObjectEnterTextSvg

D3JS demos not for beginners 

 

  • Data GeoJson
  • Maps
  • Custom Charts
  • Force Visualzation

In other session will see this in details

Data GeoJson


//Load in GeoJSON data
d3.json("https://codepen.io/jecaestevez/pen/eyNwME.js", function(json) {

  //Bind data and create one path per GeoJSON feature
  svg.selectAll("path")
    .data(json.features)
    .enter()
    .append("path")
    .attr("d", path) 
    .attr("fill","#666666");

});    
var svgWidth = 800;
var svgHeight = 800;
 

//Create SVG element
var svg = d3.select("body").append("svg")
.attr({width:svgWidth, height: svgHeight});

//Define path generator
var path = d3.geo.path();

//Load in GeoJSON data
d3.json("https://codepen.io/jecaestevez/pen/eyNwME.js", function(json) {


});    

D3JS and Google Maps

Custom Charts

D3JS Force

D3JS Force

Resources

  • https://bost.ocks.org/mike/chart/
  • https://medium.com/@c_behrens/enter-update-exit-6cafc6014c36

d3jsWorkshop_21022018

By Jesús Estévez

d3jsWorkshop_21022018

  • 855