Public
Edited
Mar 2, 2023
14 forks
Importers
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
xaxis = svg`
<svg width=600 height=40>
<g id="x-axis" transform="translate(10,20)" font-size="10" font-family="sans-serif" text-anchor="right">
<text fill="grey" text-anchor="end" x="419" y="-3">
Income per inhabitant (dollars at purchasing power parity, logarithmic scale)
</text>
<path fill="none" stroke="black" d="M60.5,6V0.5H419V6"></path>
<g class="tick" transform="translate(60.5,0)">
<line stroke="black" y2="6"></line>
<text y="16" x="-3">10</text>
</g>
<g class="tick" transform="translate(114,0)">
<line stroke="black" y2="6"></line>
<text y="16" x="-3">20</text>
</g>
<g class="tick" transform="translate(146,0)">
<line stroke="black" y2="6"></line>
<text y="16" x="-3">30</text>
</g>
<g class="tick" transform="translate(168,0)">
<line stroke="black" y2="6"></line>
<text y="16" x="-3">40</text>
</g>
<g class="tick" transform="translate(185,0)">
<line stroke="black" y2="6"></line>
<text y="16" x="-3">50</text>
</g>
<g class="tick" transform="translate(200,0)">
<line stroke="black" y2="6"></line>
</g>
<g class="tick" transform="translate(212,0)">
<line stroke="black" y2="6"></line>
</g>
<g class="tick" transform="translate(222,0)">
<line stroke="black" y2="6"></line>
</g>
<g class="tick" transform="translate(231,0)">
<line stroke="black" y2="6"></line>
</g>
<g class="tick" transform="translate(240,0)">
<line stroke="black" y2="6"></line>
<text y="16" x="-3">100</text>
</g>
<g class="tick" transform="translate(294,0)">
<line stroke="black" y2="6"></line>
<text y="16" x="-3">200</text>
</g>
<g class="tick" transform="translate(325,0)">
<line stroke="black" y2="6"></line>
<text y="16" x="-3">300</text>
</g>
<g class="tick" transform="translate(348,0)">
<line stroke="black" y2="6"></line>
</g>
<g class="tick" transform="translate(365,0)">
<line stroke="black" y2="6"></line>
</g>
<g class="tick" transform="translate(379,0)">
<line stroke="black" y2="6"></line>
</g>
<g class="tick" transform="translate(391,0)">
<line stroke="black" y2="6"></line>
</g>
<g class="tick" transform="translate(402,0)">
<line stroke="black" y2="6"></line>
</g>
<g class="tick" transform="translate(411,0)">
<line stroke="black" y2="6"></line>
</g>
<g class="tick" transform="translate(419,0)">
<line stroke="black" y2="6"></line>
<text y="16" x="-3">1 000</text>
</g>
</g>
</svg>
`
Insert cell
Insert cell
Insert cell
Insert cell
md`
\`\`\`
svg
|- g
| |- text
| | |- "Income per ..."
| |- path
|- g
| |- line
|- text
|- "10"

-------------------> CONTINUE HERE <--------------------------
(you don't have to continue once have understood the principle)

\`\`\`
`
Insert cell
Insert cell
Insert cell
Insert cell
d3 = require("d3") // importation of the d3 library
Insert cell
Insert cell
{
const svg = d3.create("svg")
const a = 179.5 // ad-hoc values for scaling
const b = -119 // ad-hoc values for scaling
const domain = [10, 1000] // values for the income
const range = [10, 550] // x-positions
svg
.attr("width", 600)
.attr("height",40)
const g = svg.append("g") // create an alias so that I can refer to it
.attr("transform", "translate(-40,20)")
.attr("font-size", 10)
.attr("font-family", "sans-serif")
.attr("text-anchor", "right")
// add and style the text
g.append("text")
.attr('fill', 'grey')
.attr('y', -3)
.attr('x', "419")
.text('Income per inhabitant (dollars at purchasing power parity, logarithmic scale)')
.attr('text-anchor', "end")
// add and style path
g.append("path")
.attr("fill", "none")
.attr("stroke", "red")
//.attr("stroke", "black")
.attr("d", "M60.5,6V0.5H419V6") // could be computed from "range"
for(let i = 1; i<4; i++){
for(let j = 1; j<10; j++){ // the limits could be computed from "domain"
let number = j*10**i
// add the ticks here
let translation = "translate(" + (a * Math.log10(number) + b) + ",0)"
// The translation could be computed from "domain" and "range"
// and we could get rid of "a" and "b".
let tick = g.append("g").attr("transform", translation)
tick.append("line")
.attr("stroke", "black")
.attr("y2", 6)
if(j <= 3){
tick.append("text")
.attr("y", 16)
.attr("x", -3)
.text(number)
}
if(number >= domain[1]) break
}
}
return svg.node()
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
countries[4].income // your solution
Insert cell
Insert cell
countries.map(country => country.life_expectancy)
Insert cell
countries.map( function(country){ return( country.life_expectancy ) } )
Insert cell
countries.filter(country => country.name=="Brazil")
Insert cell
countries.filter(country => ["Brazil", "Colombia"].includes(country.name))
Insert cell
countries.filter(country => country.population > 100000000)
Insert cell
countries
.filter( country => country.population > 100000000)
.map( country => country.name) // you chain methods one to the other
Insert cell
Insert cell
{
let emissions = [] // empty array
for(let country of countries){

emissions.push(country.co2_emissions) // this goes into the loop, adds the emission number to the array
}
return emissions
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
x = d3.scaleLinear().domain(expectancy_domain).range(x_range)
Insert cell
x(50) // an life expectancy of 50 will be mapped to x=276
Insert cell
Insert cell
pop_max = d3.max(countries, country => country.population)
Insert cell
r2 = d3.scaleSqrt().domain([0, pop_max]).range([1, 30])
Insert cell
r2(0)
Insert cell
r2(30000000)
Insert cell
r2.invert(4)
Insert cell
Insert cell
Insert cell
Insert cell
{
const graph = d3.create("svg")
.attr("width", x_range[1]+10)
.attr("height", height_1d)
for(let country of countries){
graph.append("circle")
.attr("cx", x(country.life_expectancy)) // x() used for positionning the circles
.attr("cy", height_1d/2)
.attr("r", 10 )
}
return graph.node()
}
Insert cell
Insert cell
Insert cell
{
const graph = d3.create("svg")
.attr("width", x_range[1]+10)
.attr("height", height_1d)
const x_axis = graph.append("g") // create a container
const make_x_axis = d3.axisBottom(x) // create the axis factory – we can add options here
make_x_axis(x_axis) // transforms the countainer into a proper axis
// you will often see: x_axis.call(make_x_axis), which is the same
return graph.node()
}
Insert cell
Insert cell
Insert cell
r = d3.scaleSqrt().domain([0,d3.max(countries, c => c.population)]).range([0,20])
// in case of conflict with your earlier code, you can comment either definitions
Insert cell
{
const graph = d3.create("svg")
.attr("width", x_range[1]+10)
.attr("height", height_1d)
for(let country of countries){ // 2.2
graph.append("circle")
.attr("cx", x(country.life_expectancy))
.attr("cy", height_1d/3)
.attr("r", r(country.population))
}
const x_axis = graph.append("g") // 2.3
const make_x_axis = d3.axisBottom(x)
make_x_axis(x_axis)
x_axis
.attr("transform", "translate(0,40)") // <---------- THIS IS NEW.
// Change the "dy" translation to adjust the bar vertically.
.append("text")
.text("Life expectancy (years)")
.attr("x", x_range[1])
.attr("y", -3)
.attr("text-anchor","end")
.attr("fill","grey")
return graph.node()
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function do_something(){
let circle = d3.select(this).selectAll('circle') // "this" is a special keyword
// Inside even callback functions,
// it refers to the "context" of the event
// i.e. the element that triggered the event.
let is_unselected = circle.attr("stroke-width") == 0.4 // circles start unselected with a stroke width of 0.4
circle.attr("stroke-width", is_unselected ? 4 : 0.4) // If it is unselected (thin border),
// then we select it (make it thicker)
// and conversely.
}
Insert cell
Insert cell
{
const inner_margin = 30
const outer_margin = 40
const margin = inner_margin+outer_margin
const graph = d3.create("svg")
.attr("width", width)
.attr("height", height_2d)
const x_domain = d3.extent(countries, country => country.life_expectancy)
const x_range = [margin, width-margin]
const y_domain = d3.extent(countries, country => country.income)
const y_range = [height_2d-margin, margin]
const r_domain = [0, d3.max(countries, country => country.population)]
const r_range = [0, 20]
const c_domain = ["americas", "asia", "europe", "africa"]
const c_range = ["#6EBB87", "#DA94CE", "#DE9D6C", "#2CB8EA"]
const x = d3.scaleLinear().domain(x_domain).range(x_range)
const y = d3.scaleLog().domain(y_domain).range(y_range)
const r = d3.scaleSqrt().domain(r_domain).range(r_range)
const c = d3.scaleOrdinal().domain(c_domain).range(c_range)
for(let country of countries){ // part 2
graph.append("circle")
.attr("cx", x(country.life_expectancy))
.attr("cy", y(country.income))
.attr("r", r(country.population))
.attr("fill", c(country.region))
.attr("stroke", "black")
.attr("stroke-width", 0.4)
.on("click", do_something) // <------- THIS IS THE ONLY NEW THING !
.style("cursor", "pointer") // <------- this is not 100% needed
// but it is nice to have a "pointer" mouse icon
// that will hint the user that some interaction is possible.
}
const make_x_axis = d3.axisBottom(x)
const make_y_axis = d3.axisLeft(y)
const x_axis = graph.append("g")
const y_axis = graph.append("g")
make_x_axis(x_axis)
make_y_axis(y_axis)
x_axis
.attr("transform", "translate(0,"+(height_2d-outer_margin)+")")
.append("text")
.text("Life expectancy (years)")
.attr("x", width-margin)
.attr("y", -3)
.attr("text-anchor","end")
.attr("fill","grey")
y_axis
.attr("transform", "translate("+outer_margin+",0)")
.append("text")
.text("Income per inhabitant (dollars PPP, logarithmic scale)")
.attr("transform", "rotate(-90) translate("+-250+","+-60+")")
.attr("x", 0)
.attr("y", margin)
.attr("text-anchor","start")
.attr("fill","grey")
.attr("font-size",8)
return graph.node()
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import {markdown, svg_cheatsheet} from "@katossky/data-visualisation-with-d3-js-1-3"
Insert cell
Insert cell
// TO DO: how to build a simple legend for circles and colors
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more