Public
Edited
Nov 27, 2023
Insert cell
Insert cell
ted_main.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
ted_url = FileAttachment("ted_main.csv").url();
Insert cell
ted_data = d3.csv(ted_url, d3.autoType)
Insert cell
drawVars = (
{
plotWidth: 1080,
plotHeight: 720,
margin: 50,
}
);
Insert cell
function createGraphContainer() {
const outerWidth = drawVars.plotWidth + 2 * drawVars.margin;
const outerHeight = drawVars.plotHeight + 2 * drawVars.margin;
var svg = d3.create('svg')
.attr('width', outerWidth)
.attr('height', outerHeight)
.attr("id", "graph");
svg.append('g')
// Translate g element by plotMargin, plotMargin to place inner plotting region.
.attr('transform', `translate(${drawVars.margin},${drawVars.margin})`)
.attr('id', 'plotContainer'); // Give the plot container an id so we can access it later.
return svg;
}
Insert cell
xScale = d3.scaleLog()
.domain(d3.extent(ted_data, d => d.views))
.range([0, drawVars.plotWidth]);
Insert cell
yScale = d3.scaleLog()
.domain(d3.extent(ted_data, d => d.comments))
.range([drawVars.plotHeight, 0]);
Insert cell
html`
<html>
<head>
</head>
<body>
<h2>TED Talks: Number of Views vs Comments</h2>
<div class="filter" id='letter-filter-vis'>
<span id='letter-filter-label'>Search for a TED Talk</span>
<input id='letter-filter' type='text' placeholder='Enter a name of a talk here!'>
</div>
<div id ="talks-vis"></div>
</body>
</html>
`
Insert cell
function createAxes(plotContainer) {

const xAxis = plotContainer.append('g') //create SVG <g> elt for x-axis
.attr('transform', `translate(0,${drawVars.plotHeight})`) //translate to bottom of plot
.call(d3.axisBottom(xScale)); //use axisBottom to form ticks below
const yAxis = plotContainer.append('g') //create SVG <g> elt for y-axis
.call(d3.axisLeft(yScale)); //use axisLeft to form ticks to the left
// const xAxisLabel = plotContainer.append("text")
// .attr("transform", `translate(${drawVars.plotWidth/2}, ${drawVars.plotHeight + 35})`)
// .style("text-anchor", "middle")
// .text("Views (log scale)");
// const yAxisLabel = plotContainer.append("text")
// .attr("transform", "rotate(-90)")
// .attr("y", 0 - drawVars.plotMargin/2)
// .attr("x", 0 - (drawVars.plotHeight / 2))
// .attr("dy", "1em")
// .style("text-anchor", "middle")
// .text("Comments (log scale)");
}
Insert cell
{
let graphContainer = createGraphContainer();
let plotContainer = graphContainer.select('#plotContainer');
const circleGroups = plotContainer.selectAll('circle')
.join('g');
createAxes(plotContainer);
drawTalks(ted_data, plotContainer, circleGroups);

d3.select('#letter-filter').on('change', () => {
handleDataFilters(ted_data, plotContainer, circleGroups);
});

d3.select('#talks-vis').selectAll("*").remove(); //Remove any plots that may already have been created.
d3.select('#talks-vis').append( () => graphContainer.node()); //Attach mapContainer.node() to DOM;
}
Insert cell
function handleDataFilters(ted_data, plotContainer, circleGroups) {
const letterFilter = d3.select('#letter-filter');
const letterFilterVal = letterFilter.property('value').toLowerCase();
let letterNewData = ted_data;
if (letterFilterVal) {
letterNewData = ted_data.filter(d => {
const talk_name = d.name.toLowerCase();
return talk_name.includes(letterFilterVal);
});
}

drawTalks(ted_data, plotContainer, circleGroups);

circleGroups.append('circle')
.data(letterNewData, d => d.name + "highlight")
.join(
(enter) => enter.append("circle"),
(update) => update,
(exit) => exit.remove()
)
.attr('id', "SEARCHED")
.attr('r', 5)
.attr('cx', d => xScale(d.views))
.attr('cy', d => yScale(d.comments))
.attr("fill", "#EB5E7A")
.attr("opacity", 0.8);

plotContainer.selectAll("text")
.data(letterNewData, d => d.name + "LABEL")
.enter()
.append("text")
.text(d => d.name)
.attr("id", "label")
.attr("x", function(d) {return xScale(d.views);})
.attr("y", function(d) {return yScale(d.comments);})
}
Insert cell
function drawTalks(ted_data, plotContainer, circleGroups) {
d3.select('#talks-vis').selectAll("circle").remove();
d3.select('#talks-vis').selectAll("#label").remove();
circleGroups.append('circle')
.data(ted_data, d => d.name)
.join(
(enter) => enter.append("circle"),
(update) => update,
(exit) => exit.remove()
)
//Set attributes for entering and updating elements
.attr('r', 5)
.attr('cx', d => xScale(d.views))
.attr('cy', d => yScale(d.comments))
.attr("fill", "#FEDD00")
.attr("opacity", 0.5)
.on('mouseover', function (event, d) { //Handle 'mouseover' events
d3.select(this).style('stroke', 'black');
plotContainer.append('text') //Append SVG 'text' element.
.attr('class', 'ptLabel') //Set class to 'ptLabel' so can remove easily later
.attr('x', xScale(d.views) - 10) //Set label position near its circle xScale(d.weight)
.attr('y', yScale(d.comments) - 10) //Set label position near its circle yScale(d.height)
.text(d.name);
})
.on('mouseout', function(event, d) {
d3.select(this).style('stroke', 'none');
plotContainer.selectAll('.ptLabel').remove() // Remove all ptLabels
});
}
Insert cell
d3 = require('d3@7')
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