Published
Edited
Mar 18, 2022
2 forks
1 star
Insert cell
Insert cell
Insert cell
Insert cell
viewof select1 = {
const WIDTH = 300
const HEIGHT = 100
const container = DOM.svg(WIDTH, HEIGHT)
container.innerHTML = `<circle cx=${WIDTH / 2} cy=${HEIGHT / 2} r="30" />`
// prendre l'élément "svg" défini plus haut
const svg = d3.select(container)
// et l'élément "circle" appartenant à l'élément "svg"
const circle = svg.select('circle')
// y ajouter un attribut "fill" avec la valeur "red"
circle.attr('fill', 'red')
return container
}
Insert cell
Insert cell
viewof select2 = {
const WIDTH = 300
const HEIGHT = 100
const container = DOM.svg(WIDTH, HEIGHT)
container.innerHTML = `<circle cx=${WIDTH / 2} cy=${HEIGHT / 2} r="30" />`
// prendre l'élément "circle"
const circle = container.getElementsByTagName('circle')[0]
// y ajouter un attribut "fill" avec la valeur "red"
circle.setAttribute('fill', 'red')
return container
}
Insert cell
Insert cell
viewof select3 = {
const WIDTH = 300
const HEIGHT = 100
const container = DOM.svg(WIDTH, HEIGHT)
// prendre l'élément "svg"
const svg = d3.select(container)
// et y ajouter un élément "rect"
const rect = svg.append('rect')
.attr('x', 20)
.attr('y', 20)
.attr('width', WIDTH - 40)
.attr('height', HEIGHT - 40)
return container
}
Insert cell
Insert cell
viewof select4 = {
const WIDTH = 300
const HEIGHT = 100
const container = DOM.svg(WIDTH, HEIGHT)
// créer un élément "rect"
// pour les éléments HTML de base nous pouvons utiliser .createElement('p') par exemple
// pour les éléments SVG, il nous faut déclarer le "name space"
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('x', 20)
rect.setAttribute('y', 20)
rect.setAttribute('width', WIDTH - 40)
rect.setAttribute('height', HEIGHT - 40)
// ajouter le rectangle à l'élément parent
container.appendChild(rect)
return container
}
Insert cell
Insert cell
viewof select5 = {
const WIDTH = 500
const HEIGHT = 100
const container = DOM.svg(WIDTH, HEIGHT)
container.innerHTML = `
<circle cx="100" cy=${HEIGHT / 2} r="30" />
<circle cx="200" cy=${HEIGHT / 2} r="30" />
<circle cx="300" cy=${HEIGHT / 2} r="30" />
`
const svg = d3.select(container)
const circles = svg.selectAll('circle')
.attr('fill', 'yellow')
return container
}
Insert cell
Insert cell
viewof select6 = {
const WIDTH = 500
const HEIGHT = 100
const container = DOM.svg(WIDTH, HEIGHT)
container.innerHTML = `
<circle cx="100" cy=${HEIGHT / 2} r="30" />
<circle cx="200" cy=${HEIGHT / 2} r="30" />
<circle cx="300" cy=${HEIGHT / 2} r="30" />
`
// nous utilisons Array.from parce qu'une liste .getElementsByTagName n'est pas itérable avec .forEach
const circles = Array.from(container.getElementsByTagName('circle'))
// une fonction pour ajouter l'attribut "fill"
const addYellowFill = circle => circle.setAttribute('fill', 'yellow')
// appliquer la fonction aux cercles
circles.forEach(addYellowFill)
return container
}
Insert cell
Insert cell
viewof select7 = {
const WIDTH = 300
const HEIGHT = 100
const container = DOM.svg(WIDTH, HEIGHT)
container.innerHTML = `<circle cx=${WIDTH / 2} cy=${HEIGHT / 2} r="10" />`
let r = 10
const svg = d3.select(container)
const circle = svg.select('circle')
.on('click', () => {
r++
circle.attr('r', r)
})
return container
}
Insert cell
Insert cell
viewof select8 = {
const WIDTH = 300
const HEIGHT = 100
const container = DOM.svg(WIDTH, HEIGHT)
container.innerHTML = `<circle cx=${WIDTH / 2} cy=${HEIGHT / 2} r="10" />`
let r = 10
const circle = container.getElementsByTagName('circle')[0]
circle.addEventListener('click', () => {
r++
circle.setAttribute('r', r)
})
return container
}
Insert cell
Insert cell
viewof data1 = {
const container = DOM.element('ul')
// les données
const DATA = [4, 6, 2, 8, 1]
// l'élément <ul>
const ul = d3.select(container)
/*
.selectAll() selectionne des éléments qui n'existent pas encore
nous voulons créer un élément <li> pour chaque donnée dans DATA
.data() défini les données que nous souhaitons joindre
quand une donnée est ajoutée --> .enter()
nous ajoutons un élément <li> à <ul> --> .append('li')
.text() ajoute chaque donnée à l'intérieur de <li> --> <li>4</li>
*/
ul.selectAll('li')
.data(DATA)
.enter()
.append('li')
.text(d => d)
return container
}
Insert cell
Insert cell
viewof data2 = {
const container = DOM.element('ul')
const DATA = [4, 6, 2, 8, 1]
const ul = d3.select(container)
ul.selectAll('li')
.data(DATA)
.enter()
.append('li')
.text((d, i) => `Donnée: ${d}, indexe: ${i}`)
return container
}
Insert cell
Insert cell
viewof data3 = {
const container = DOM.element('ul')
const DATA = [4, 6, 2, 8, 1]
const ul = d3.select(container)
ul.selectAll('li')
.data(DATA)
.enter()
.append('li')
// si d est plus grand que 4, la couleur est rouge
.style('color', d => d > 4 ? 'red' : 'black')
// si i est plus petit que 3, le texte est en gras
.style('font-weight', (d, i) => i < 3 ? 'bold' : 'normal')
.text((d, i) => `Donnée: ${d}, indexe: ${i}`)
return container
}
Insert cell
Insert cell
viewof bar1 = {
const WIDTH = width
const HEIGHT = width / 3
const container = DOM.svg(WIDTH, HEIGHT)
const DATA = [4, 6, 2, 8, 1]
const MARGIN = 5 // espace entre les bâtons
const BAR_WIDTH = WIDTH / DATA.length // largeur des bâtons
const svg = d3.select(container)
svg.selectAll('rect')
.data(DATA)
.enter()
.append('rect')
// la position horizontale
.attr('x', (d, i) => i * BAR_WIDTH)
// la largeur
.attr('width', BAR_WIDTH - MARGIN)
// la position verticale
.attr('y', d => HEIGHT - d)
// la hauteur
.attr('height', d => d)

return container
}
Insert cell
Insert cell
viewof bar2 = {
const WIDTH = width
const HEIGHT = width / 3
const container = DOM.svg(WIDTH, HEIGHT)
const DATA = [4, 6, 2, 8, 1]
const MARGIN = 5
const BAR_WIDTH = WIDTH / DATA.length
const svg = d3.select(container)
// nous allons utiliser une échelle linéaire
const heightScale = d3.scaleLinear()
// les données en entrée
.domain([0, d3.max(DATA)]) // d3.max retourne le maxium d'une liste
// les données en sortie
.range([0, HEIGHT])
// comme 8 est la valeur maximale, heightScale(8) retourne la hauteur HEIGHT
// heightScale(4) retourne la moitié de HEIGHT ...
svg.selectAll('rect')
.data(DATA)
.enter()
.append('rect')
.attr('x', (d, i) => i * BAR_WIDTH)
.attr('width', BAR_WIDTH - MARGIN)
// utiliser heightScale pour y et height
.attr('y', d => HEIGHT - heightScale(d))
.attr('height', heightScale)

return container
}
Insert cell
Insert cell
viewof bar3 = {
const WIDTH = width
const HEIGHT = width / 3
const container = DOM.svg(WIDTH, HEIGHT)
const DATA = [4, 6, 2, 8, 1]
const MARGIN = 5
const BAR_WIDTH = WIDTH / DATA.length
const svg = d3.select(container)
const heightScale = d3.scaleLinear()
.domain([0, d3.max(DATA)])
.range([0, HEIGHT])
// l'échelle de couleur
const fillScale = d3.scaleLinear()
.domain([0, d3.max(DATA)])
.range(['white', 'indianred'])
svg.selectAll('rect')
.data(DATA)
.enter()
.append('rect')
.attr('x', (d, i) => i * BAR_WIDTH)
.attr('width', BAR_WIDTH - MARGIN)
.attr('y', d => HEIGHT - heightScale(d))
.attr('height', heightScale)
// appliquée à l'attribut fill
.attr('fill', fillScale)
return container
}
Insert cell
Insert cell
viewof bar4 = {
const WIDTH = width
const HEIGHT = width / 3
const container = DOM.svg(WIDTH, HEIGHT)
const MARGIN = 5
const svg = d3.select(container)
const DATA = [
{ nom: 'Lausanne', population: 138905 },
{ nom: 'Yverdon-les-Bains', population: 30143 },
{ nom: 'Montreux', population: 26574 },
{ nom: 'Renens', population: 21036 },
{ nom: 'Nyon', population: 20533 },
{ nom: 'Vevey', population: 19827 },
]
const BAR_WIDTH = WIDTH / DATA.length
// maintenant "d" représente un objet
// par exemple: { nom: 'Lausanne', population: 138905 }
const heightScale = d3.scaleLinear()
.domain([0, d3.max(DATA, d => d.population)]) // le maximum de population
.range([0, HEIGHT])
svg.selectAll('rect')
.data(DATA)
.enter()
.append('rect')
.attr('x', (d, i) => i * BAR_WIDTH)
.attr('width', BAR_WIDTH - MARGIN)
// nous devons passer d.population à heightScale
.attr('y', d => HEIGHT - heightScale(d.population))
.attr('height', d => heightScale(d.population))

return container
}
Insert cell
Insert cell
viewof bar5 = {
const WIDTH = width
const HEIGHT = width / 3
const container = DOM.svg(WIDTH, HEIGHT)
const MARGIN = 5
// faisons de la place pour les noms
const MARGIN_BOTTOM = HEIGHT / 10
const GRAPH_HEIGHT = HEIGHT - MARGIN_BOTTOM
const svg = d3.select(container)
const DATA = [
{ nom: 'Lausanne', population: 138905 },
{ nom: 'Yverdon-les-Bains', population: 30143 },
{ nom: 'Montreux', population: 26574 },
{ nom: 'Renens', population: 21036 },
{ nom: 'Nyon', population: 20533 },
{ nom: 'Vevey', population: 19827 },
]
const BAR_WIDTH = WIDTH / DATA.length
const heightScale = d3.scaleLinear()
.domain([0, d3.max(DATA, d => d.population)])
.range([0, GRAPH_HEIGHT]) // la nouvelle hauteur
// un groupe pour pouvoir déplacer les bâtons
const bars = svg.append('g')
.attr('transform', `translate(0,-${MARGIN_BOTTOM})`)
bars.selectAll('rect')
.data(DATA)
.enter()
.append('rect')
.attr('x', (d, i) => i * BAR_WIDTH)
.attr('width', BAR_WIDTH - MARGIN)
.attr('y', d => HEIGHT - heightScale(d.population))
.attr('height', d => heightScale(d.population))
// les éléments <text>
svg.selectAll('text')
.data(DATA)
.enter()
.append('text')
.attr('x', (d, i) => i * BAR_WIDTH + BAR_WIDTH / 2)
.attr('y', HEIGHT - MARGIN_BOTTOM + 20)
.attr('text-anchor', 'middle')
.text(d => d.nom)
return container
}
Insert cell
Insert cell
viewof bar6 = {
const WIDTH = width
const HEIGHT = width / 3
const container = DOM.svg(WIDTH, HEIGHT)
const MARGIN = 5
const MARGIN_BOTTOM = HEIGHT / 10
const GRAPH_HEIGHT = HEIGHT - MARGIN_BOTTOM
// faisons de la place à gauche des bâtons
const MARGIN_LEFT = WIDTH / 20
const GRAPH_WIDTH = WIDTH - MARGIN_LEFT
const svg = d3.select(container)
const DATA = [
{ nom: 'Lausanne', population: 138905 },
{ nom: 'Yverdon-les-Bains', population: 30143 },
{ nom: 'Montreux', population: 26574 },
{ nom: 'Renens', population: 21036 },
{ nom: 'Nyon', population: 20533 },
{ nom: 'Vevey', population: 19827 },
]
const BAR_WIDTH = GRAPH_WIDTH / DATA.length // la nouvelle largeur du graphique
const heightScale = d3.scaleLinear()
.domain([0, d3.max(DATA, d => d.population)])
.range([0, GRAPH_HEIGHT])
const bars = svg.append('g')
// déplacer les bâtons sur la droite
.attr('transform', `translate(${MARGIN_LEFT},-${MARGIN_BOTTOM})`)
bars.selectAll('rect')
.data(DATA)
.enter()
.append('rect')
.attr('x', (d, i) => i * BAR_WIDTH)
.attr('width', BAR_WIDTH - MARGIN)
.attr('y', d => HEIGHT - heightScale(d.population))
.attr('height', d => heightScale(d.population))
// un groupe pour déplacer les noms sur la droite
const cityNames = svg.append('g')
.attr('transform', `translate(${MARGIN_LEFT}, 0)`)
cityNames.selectAll('text')
.data(DATA)
.enter()
.append('text')
.attr('x', (d, i) => i * BAR_WIDTH + BAR_WIDTH / 2)
.attr('y', HEIGHT - MARGIN_BOTTOM + 20)
.attr('text-anchor', 'middle')
.text(d => d.nom)
// créer un axe en fonction de l'échelle
const axisY = d3.axisLeft().scale(heightScale)

// créer un nouveau groupe et y attacher l'axe
svg.append('g')
.attr('transform', `translate(${MARGIN_LEFT - 3})`)
.call(axisY)

return container
}
Insert cell
Insert cell
viewof bar7 = {
const WIDTH = width
const HEIGHT = width / 3
const container = DOM.svg(WIDTH, HEIGHT)
const MARGIN = 5
const MARGIN_BOTTOM = HEIGHT / 10
const GRAPH_HEIGHT = HEIGHT - MARGIN_BOTTOM
const MARGIN_LEFT = WIDTH / 20
const GRAPH_WIDTH = WIDTH - MARGIN_LEFT
const svg = d3.select(container)
const DATA = [
{ nom: 'Lausanne', population: 138905 },
{ nom: 'Yverdon-les-Bains', population: 30143 },
{ nom: 'Montreux', population: 26574 },
{ nom: 'Renens', population: 21036 },
{ nom: 'Nyon', population: 20533 },
{ nom: 'Vevey', population: 19827 },
]
const BAR_WIDTH = GRAPH_WIDTH / DATA.length
// passons d'une échelle de hauteur à une échelle de y
const yScale = d3.scaleLinear()
.domain([0, d3.max(DATA, d => d.population)])
.range([GRAPH_HEIGHT, 0]) // a été inversé
const bars = svg.append('g')
// la valeur y est calculée depuis le haut
// nous n'avons plus besoin de la marge en bas
.attr('transform', `translate(${MARGIN_LEFT}, 0)`)
bars.selectAll('rect')
.data(DATA)
.enter()
.append('rect')
.attr('x', (d, i) => i * BAR_WIDTH)
.attr('width', BAR_WIDTH - MARGIN)
.attr('y', d => yScale(d.population)) // utiliser yScale pour y
.attr('height', d => GRAPH_HEIGHT - yScale(d.population)) // modifier la hauteur
.attr('fill', 'steelblue') // un peu de couleur
const cityNames = svg.append('g')
.attr('transform', `translate(${MARGIN_LEFT}, 0)`)
cityNames.selectAll('text')
.data(DATA)
.enter()
.append('text')
.attr('x', (d, i) => i * BAR_WIDTH + BAR_WIDTH / 2)
.attr('y', HEIGHT - MARGIN_BOTTOM + 20)
.attr('text-anchor', 'middle')
.attr('font-family', 'sans-serif') // pour avoir la même typographie que sur l'axe y
.text(d => d.nom)
// utiliser la nouvelle échelle pour l'axe
const axisY = d3.axisLeft().scale(yScale)
// formatter les valeurs
.tickFormat(d => `${d / 1000}k`)
// le nombre de valeurs présentées
.ticks(5)

svg.append('g')
.attr('transform', `translate(${MARGIN_LEFT - 3})`)
.call(axisY)
return container
}
Insert cell
Insert cell
sales = [
{ name: 'Pommes', value: 23 },
{ name: 'Poires', value: 12 },
{ name: 'Bananes', value: 18 },
]
Insert cell
Insert cell
getPieData = d3.pie().value(d => d.value)
Insert cell
Insert cell
pieData = getPieData(sales)
Insert cell
Insert cell
viewof pie1 = {
const WIDTH = width / 3
const HEIGHT = width / 4
const container = DOM.svg(WIDTH, HEIGHT)
const svg = d3.select(container)
// une fonction pour transformer les angles en attribut d
const arcCreator = d3.arc()
.innerRadius(0)
.outerRadius(HEIGHT / 2)
svg.selectAll('path')
.data(pieData) // créé plus haut
.enter()
.append('path')
.attr('d', arcCreator)
return container
}
Insert cell
Insert cell
viewof pie2 = {
const WIDTH = width / 3
const HEIGHT = width / 4
const container = DOM.svg(WIDTH, HEIGHT)
const svg = d3.select(container)
const arcCreator = d3.arc()
.innerRadius(0)
.outerRadius(HEIGHT / 2)
// une fonction pour la couleur
const color = ({ data }) => {
switch (data.name) {
case 'Bananes': return 'gold'
case 'Poires': return 'limegreen'
default: return 'indianred'
}
}
// un groupe pour centrer le camembert
const pie = svg.append('g')
.attr('transform', `translate(${HEIGHT / 2}, ${HEIGHT / 2})`)
pie.selectAll('path')
.data(pieData)
.enter()
.append('path')
.attr('d', arcCreator)
// un peu de couleur
.attr('fill', color)
return container
}
Insert cell
Insert cell
viewof pie3 = {
const WIDTH = width / 3
const HEIGHT = width / 4
const container = DOM.svg(WIDTH, HEIGHT)
const svg = d3.select(container)
const arcCreator = d3.arc()
.innerRadius(0)
.outerRadius(HEIGHT / 2 - 10) // pour que tout le camembert soit visible
const color = ({ data }) => {
switch (data.name) {
case 'Bananes': return 'gold'
case 'Poires': return 'limegreen'
default: return 'indianred'
}
}
const pie = svg.append('g')
.attr('transform', `translate(${HEIGHT / 2}, ${HEIGHT / 2})`)
pie.selectAll('path')
.data(pieData)
.enter()
.append('path')
.attr('d', arcCreator)
.attr('fill', color)
// un texte pour chaque tranche
pie.selectAll('text')
.data(pieData)
.enter()
.append('text')
// .centroid permet de trouver le centre de la tranche
.attr('transform', d => `translate(${arcCreator.centroid(d)})`)
.attr('text-anchor', 'middle')
.text(d => d.data.name)
// la légende
const legend = svg.append('g')
.attr('transform', `translate(${HEIGHT-10})`)
const RECT_WIDTH = 20
// les carrés de couleur3.line()
legend.selectAll('rect')
.data(pieData)
.enter()
.append('rect')
.attr('y', (d, i) => i * RECT_WIDTH)
.attr('width', RECT_WIDTH)
.attr('height', RECT_WIDTH)
.attr('fill', color)
// les noms de fruits
legend.selectAll('text')
.data(pieData)
.enter()
.append('text')
.attr('x', RECT_WIDTH * 1.5)
.attr('y', (d, i) => i * RECT_WIDTH + RECT_WIDTH * 0.75)
.attr('width', RECT_WIDTH)
.attr('height', RECT_WIDTH)
.text(d => d.data.name)
return container
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof line1 = {
const WIDTH = width
const HEIGHT = width / 4
const container = DOM.svg(WIDTH, HEIGHT)
const svg = d3.select(container)
// spécifier le format de date
const formatDate = d3.timeParse('%Y-%m-%d')
const DATA = bitcoinPrices.map(d => ({ ...d, date: formatDate(d.date) }))
// échelle de temps pour l'axe X
const scaleX = d3.scaleTime()
.range([0, WIDTH])
.domain(d3.extent(DATA, d => d.date))
// échelle linéaire pour le prix de cloture
const scaleY = d3.scaleLinear()
.range([HEIGHT, 0])
.domain(d3.extent(DATA, d => d.close))

// la fonction d3.line() pour créer l'attribut "d"
const linePathCreator = d3.line()
// quelle échelle, quelle donnée pour l'axe X
.x(d => scaleX(d.date))
// quelle échelle, quelle donnée pour l'axe Y
.y(d => scaleY(d.close))

// ajouter une courbe au SVG
const line = svg.append('path')
// utiliser linePathCreator pour créer l'attribut "d"
.attr('d', linePathCreator(DATA))
.attr('fill', 'none')
.attr('stroke', 'red')

return container
}
Insert cell
Insert cell
viewof line2 = {
const WIDTH = width
const HEIGHT = width / 4
const container = DOM.svg(WIDTH, HEIGHT)
const svg = d3.select(container)
const formatDate = d3.timeParse('%Y-%m-%d')
const DATA = bitcoinPrices.map(d => ({ ...d, date: formatDate(d.date) }))
const scaleX = d3.scaleTime()
.range([0, WIDTH])
.domain(d3.extent(DATA, d => d.date))
const scaleY = d3.scaleLinear()
.range([HEIGHT, 0])
.domain(d3.extent(DATA, d => d.close))

// créateur de ligne fait maison
const linePathCreator = DATA =>
DATA
// calculer x et y
.map(d => ([scaleX(d.date), scaleY(d.close)]))
// ajouter M au premier, L aux autres
.map(([x, y], index) => `${index === 0 ? 'M' : 'L'} ${x} ${y}` )
// joindre les coordonnés
.join(' ')

const line = svg.append('path')
.attr('d', linePathCreator(DATA))
.attr('fill', 'none')
.attr('stroke', 'red')

return container
}
Insert cell
Insert cell
viewof line3 = {
const WIDTH = width
const HEIGHT = width / 4
const container = DOM.svg(WIDTH, HEIGHT)
const svg = d3.select(container)
const formatDate = d3.timeParse('%Y-%m-%d')
const DATA = bitcoinPrices.map(d => ({ ...d, date: formatDate(d.date) }))
const scaleX = d3.scaleTime()
.range([0, WIDTH])
.domain(d3.extent(DATA, d => d.date))
const scaleY = d3.scaleLinear()
.range([HEIGHT, 0])
.domain(d3.extent(DATA, d => d.close))

const linePathCreator = d3.line()
.x(d => scaleX(d.date))
.y(d => scaleY(d.close))
.curve(d3.curveBasis) // ici

const line = svg.append('path')
.attr('d', linePathCreator(DATA))
.attr('fill', 'none')
.attr('stroke', 'red')

return container
}
Insert cell
Insert cell
viewof line4 = {
const WIDTH = width
const HEIGHT = width / 4
const container = DOM.svg(WIDTH, HEIGHT)
const svg = d3.select(container)
const formatDate = d3.timeParse('%Y-%m-%d')
const DATA = bitcoinPrices.map(d => ({ ...d, date: formatDate(d.date) }))
const scaleX = d3.scaleTime()
.range([0, WIDTH])
.domain(d3.extent(DATA, d => d.date))
const scaleY = d3.scaleLinear()
.range([HEIGHT, 0])
.domain(d3.extent(DATA, d => d.close))

const linePathCreator = d3.line()
.x(d => scaleX(d.date))
.y(d => scaleY(d.close))
.curve(d3.curveStep) // ici

const line = svg.append('path')
.attr('d', linePathCreator(DATA))
.attr('fill', 'none')
.attr('stroke', 'red')

return container
}
Insert cell
Insert cell
viewof area = {
const WIDTH = width
const HEIGHT = width / 4
const container = DOM.svg(WIDTH, HEIGHT)
const svg = d3.select(container)
const formatDate = d3.timeParse('%Y-%m-%d')
const DATA = bitcoinPrices.map(d => ({ ...d, date: formatDate(d.date) }))
const scaleX = d3.scaleTime()
.range([0, WIDTH])
.domain(d3.extent(DATA, d => d.date))
const scaleY = d3.scaleLinear()
.range([HEIGHT, 0])
.domain(d3.extent(DATA, d => d.close))

// la fonction d3.area() pour créer l'attribut "d"
const pathCreator = d3.area()
// quelle échelle, quelle donnée pour l'axe X
.x(d => scaleX(d.date))
// pour l'axe vertical nous devons définir de où à où remplir
// ici la ligne de base correspond à la valeur minimum
.y0(scaleY(d3.min(DATA, d => d.close)))
.y1(d => scaleY(d.close))

const line = svg.append('path')
.attr('d', pathCreator(DATA))
.attr('fill', 'steelblue')
return container
}
Insert cell
Insert cell
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