Published
Edited
Apr 21, 2021
Insert cell
Insert cell
Insert cell
Insert cell
singleVote = {
const container = d3.select(DOM.svg(1000, 100));
const limit = 10
const pinkGroup = container
.append("g")
.attr("transform", () => "translate(" + 40 + "," + 20 + ")")
.attr("id", "pinkGroup")
.attr('fill', '#ff96ca')
.attr('opacity', 0.2)
.attr("value", 0)
pinkGroup
.append('circle')
.attr('r', '20')
pinkGroup
.append("text")
.text(pinkGroup.attr("value"))
.style("font", " 1.2em sans-serif")
.style("text-anchor", "middle")
.style("fill", "blue")
.attr("dy", "0.35em")
// attach a counter to the pinkGroup; it increments value by 1 each time it is clicked on
pinkGroup.on("click", function() {
let pinkScore = +pinkGroup.attr("value") // the + converts a string to an integer
if (pinkScore >= limit) return;
pinkScore += 1;
pinkGroup.selectAll("text").text(pinkScore); // change the text to show new value
pinkGroup.attr("value", pinkScore); // change the value itself
pinkGroup.attr("opacity", pinkScore*0.1 + 0.1) // for fun, adjust the opacity as well
});
return container.node();
}
Insert cell
Insert cell
Insert cell
splitVotes = {
const container = d3.select(DOM.svg(1000, 100));
const limit = 10
const pinkGroup = container
.append("g")
.attr("transform", () => "translate(" + 40 + "," + 20 + ")")
.attr("id", "pinkGroup")
.attr('fill', '#ff96ca')
.attr("value", 0)
pinkGroup
.append('circle')
.attr('r', '20')
pinkGroup
.append("text")
.text(pinkGroup.attr("value"))
.style("font", " 1.2em sans-serif")
.style("text-anchor", "middle")
.style("fill", "blue")
.attr("dy", "0.35em")
// Repeat everything for greenGroup that we did for pinkGroup
const greenGroup = container
.append("g")
.attr("transform", () => "translate(" + 100 + "," + 20 + ")")
.attr("id", "greenGroup")
.attr("fill","lime")
.attr("value", limit)
greenGroup
.append('circle')
.attr('r', '20')
greenGroup
.append("text")
.text(greenGroup.attr("value"))
.style("font", " 1.2em sans-serif")
.style("text-anchor", "middle")
.style("fill", "blue")
.attr("dy", "0.35em")
pinkGroup.on("click", function(d) {
let pinkScore = +pinkGroup.attr("value")
let greenScore = +greenGroup.attr("value")
if (pinkScore >= limit) return;
pinkScore += 1;
greenScore -= 1;
pinkGroup.selectAll("text").text(pinkScore);
pinkGroup.attr("value", pinkScore);
greenGroup.selectAll("text").text(greenScore);
greenGroup.attr("value", greenScore);
});
greenGroup.on("click", function(d) {
let pinkScore = +pinkGroup.attr("value")
let greenScore = +greenGroup.attr("value")
if (greenScore >= limit) return;
greenScore += 1;
pinkScore -= 1;
greenGroup.select("text").text(greenScore);
greenGroup.attr("value", greenScore);
pinkGroup.select("text").text(pinkScore);
pinkGroup.attr("value", pinkScore);
});

return container.node();
}
Insert cell
Insert cell
splitVotesWithFunctionCalls = {
const container = d3.select(DOM.svg(1000, 100));
const limit = 10;
// define some css commands for styling text
const styleText = `text {
font: 1.2em sans-serif;
text-anchor: middle;
fill: blue;
}`
// all the text in this container is styled by this style declaration
container.append("style").text(styleText);
const pinkGroup = container
.append("g")
.attr("transform", () => "translate(" + 40 + "," + 20 + ")")
.attr("id", "pinkGroup")
.attr('fill', '#ff96ca')
const greenGroup = container
.append("g")
.attr("transform", () => "translate(" + 100 + "," + 20 + ")")
.attr("id", "greenGroup")
.attr("fill","lime")
function init(svg, value) {
// add code in here to change opacity according to the value
svg.attr("value", value);
svg.append("circle")
.attr("r", '20')
// notice we no longer have to specify the text style here,
// because we defined it for the entire container in the css style declaration
svg.append("text")
.text(svg.attr("value"))
.attr("dy", "0.35em")
}
// call the initialization functions
init(pinkGroup, 3)
init(greenGroup, limit-3);
// the + sign is to convert the value from string to integer
function updateScores(svg1, svg2) {
let score1 = +svg1.attr("value");
let score2 = +svg2.attr("value");
if (score1 >= limit) return;
score1 += 1;
score2 -= 1;
svg1.select("text").text(score1);
svg1.attr("value", score1);
svg2.select("text").text(score2);
svg2.attr("value", score2);
// add code here to update the opacity
}
// Notice the order in which updateScores is given arguments
pinkGroup.on("click", function(d) {
updateScores(pinkGroup, greenGroup);
});
greenGroup.on("click", function(d) {
updateScores(greenGroup, pinkGroup);
});
return container.node();
}
Insert cell
Insert cell
Insert cell
// html`<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">`
Insert cell
Insert cell
// html`<link type="text/css" href="${await FileAttachment("yourfilenamehere.css").url()}" rel="stylesheet" />`
Insert cell
Insert cell
splitVotesGrowRectangles = {
const container = d3.select(DOM.svg(1000, 300));
const limit = 10;
// define some css commands for styling text
const styleText = `text {
font: 1.2em sans-serif;
text-anchor: middle;
fill: blue;
}`
container.append("style").text(styleText);
const rectHeight = 20;
const pinkGroup = container
.append("g")
.attr("transform", () => "translate(" + 40 + "," + 20 + ")")
.attr("id", "pinkGroup")
.attr('fill', '#ff96ca')
const greenGroup = container
.append("g")
.attr("transform", () => "translate(" + 100 + "," + 20 + ")")
.attr("id", "greenGroup")
.attr("fill","lime")
function init(svg, value) {
svg.attr("value", value);
svg.append("circle")
.attr("r", '20')
svg.append("text")
.text(svg.attr("value"))
.attr("dy", "0.35em")
// this is code to initialize the rectangles
// we need a dataset of values to bind the rectangles to, from 1 to value
const arrayOfInts = d3.range(1,value+1);
const rectHeight = 20;
// this creates rectangles at a constant x position, with y a function of arrayOfInts
// it is very important to create a unique id for each rectangle so we can select them later
svg.selectAll("rect")
.data(arrayOfInts)
.enter().append("rect")
.attr("width", 40).attr("height", rectHeight)
.style("fill", "blue").attr("stroke", "pink")
.attr("x", -20 )
.attr("y", d => d*rectHeight)
.attr("id", d => svg.attr("id") + "rect" + d);
}
// call the initialization functions
init(pinkGroup, 3)
init(greenGroup, limit-3);
function updateScores(svg1, svg2) {
let score1 = +svg1.attr("value");
let score2 = +svg2.attr("value");
if (score1 >= limit) return;
score1 += 1;
score2 -= 1;
// add rectangle to svg1; x value stays constant;
// y is a function of the current value; this grows the rectangle at the bottom
svg1
.append("rect").attr("width", 40).attr("height", rectHeight)
.style("fill", "blue").attr("stroke", "pink")
.attr("x", -20 )
.attr("y", score1*rectHeight)
.attr("id", svg1.attr("id") + "rect" + score1);
// remove the lowest rectangle from svg2;
// to make this work, d3 has to know the unique id of that rectangle
// we build a string to hold the name of that id
const rectToRemove = "#" + svg2.attr("id") + "rect" + svg2.attr("value")
d3.selectAll(rectToRemove).remove();
svg1.select("text").text(score1);
svg1.attr("value", score1);
svg2.select("text").text(score2);
svg2.attr("value", score2);
}
// Notice the order in which updateScores is given arguments
pinkGroup.on("click", function(d) {
updateScores(pinkGroup, greenGroup);
});
greenGroup.on("click", function(d) {
updateScores(greenGroup, pinkGroup);
});
return container.node();
}
Insert cell
Insert cell
Insert cell
practiceImages = { // based on https://fabiofranchino.com/blog/how-to-load-image-in-svg-with-d3js/
const svg = d3.select(DOM.svg(1000, 200));
const numImages = 4
const arrayOfInts = d3.range(1,numImages +1);
const imageHeight = 80;
let myimage = svg.selectAll("image")
.data(arrayOfInts)
.enter().append('image')
.attr('xlink:href', 'https://upload.wikimedia.org/wikipedia/commons/4/47/Golf_ball.svg')
.attr('width', imageHeight)
.attr('height', imageHeight)
.attr('x', (d,i) => i*imageHeight + 10)
.attr('y', 20)
return svg.node();
}
Insert cell
Insert cell
Insert cell
splitVotesGrowGolfBalls = {
const container = d3.select(DOM.svg(1000, 300));
const limit = 10;
const imageLink = 'https://upload.wikimedia.org/wikipedia/commons/4/47/Golf_ball.svg';
const imageHeight = 20
// define some css commands for styling text
const styleText = `text {
font: 1.2em sans-serif;
text-anchor: middle;
fill: blue;
}`
container.append("style").text(styleText);
const pinkGroup = container
.append("g")
.attr("transform", () => "translate(" + 40 + "," + 20 + ")")
.attr("id", "pinkGroup")
.attr('fill', '#ff96ca')
const greenGroup = container
.append("g")
.attr("transform", () => "translate(" + 100 + "," + 20 + ")")
.attr("id", "greenGroup")
.attr("fill","lime")
function init(svg, value) {
svg.attr("value", value);
svg.append("circle")
.attr("r", '20')
svg.append("text")
.text(svg.attr("value"))
.attr("dy", "0.35em")
// this is code to initialize the rectangles
// we need a dataset of values to bind the rectangles to, from 1 to value
const arrayOfInts = d3.range(1,value+1);
// this creates rectangles at a constant x position, with y a function of arrayOfInts
// it is very important to create a unique id for each rectangle so we can select them later
svg.selectAll("image")
.data(arrayOfInts)
.enter().append("image")
.attr('xlink:href', imageLink)
.attr("width", imageHeight)
.attr("height", imageHeight)
.attr("x", -10 )
.attr("y", d => d*imageHeight)
.attr("id", d => svg.attr("id") + "image" + d);
}
// call the initialization functions
init(pinkGroup, 3)
init(greenGroup, limit-3);
function updateScores(svg1, svg2) {
let score1 = +svg1.attr("value");
let score2 = +svg2.attr("value");
if (score1 >= limit) return;
score1 += 1;
score2 -= 1;
// add rectangle to svg1; x value stays constant;
// y is a function of the current value; this grows the rectangle at the bottom
svg1
.append("image").attr('xlink:href', imageLink)
.attr("width", imageHeight).attr("height", imageHeight)
.attr("x", -10 )
.attr("y", score1*imageHeight)
.attr("id", svg1.attr("id") + "image" + score1);
// remove the lowest rectangle from svg2;
// to make this work, d3 has to know the unique id of that rectangle
// we build a string to hold the name of that id
const imageToRemove = "#" + svg2.attr("id") + "image" + svg2.attr("value")
d3.selectAll(imageToRemove).remove();
svg1.select("text").text(score1);
svg1.attr("value", score1);
svg2.select("text").text(score2);
svg2.attr("value", score2);
}
// Notice the order in which updateScores is given arguments
pinkGroup.on("click", function(d) {
updateScores(pinkGroup, greenGroup);
});
greenGroup.on("click", function(d) {
updateScores(greenGroup, pinkGroup);
});
return container.node();
}
Insert cell
Insert cell
Insert cell
practiceDivs = {
// d3.create() creates an outer div to which we can append other things
const outerDiv = d3.create("div").attr("id", "outerDiv").attr("height", 20);
// append a <p></p>
outerDiv.append("p").text("I'm in outer space!");
// append an svg of height 20 and to that append a purple circle
outerDiv.append("svg").attr("id", "svg1").attr("height", 20)
.append("circle").attr("cx",10).attr("cy", 10).attr("r",10).attr("fill","purple")
// append another div of height 20
const innerDiv = outerDiv.append("div").attr("id", "innerDiv").attr("height", 20);
// and more text with <p></p>
innerDiv.append("p").text("I'm on earth!")
// and nest within that inner div another svg of height 200, and add to that a pink circle
innerDiv.append("svg").attr("id", "svg2").attr("height", 200)
.append("circle").attr("cx",10).attr("cy", 10).attr("r",10).attr("fill","pink")
return outerDiv.node();
}
Insert cell
Insert cell
Insert cell
{
let div = d3.create('div');
// it is key that we name this div with a unique ID so we can select it below
let selector = div.append('select').attr("id", "dropdown1");
const allMessages = [ {display: "Choose a time frame", value: "none"},
{display: "1 year", value: "1%"},
{display: "5 years", value: "6%"},
{display: "10 years", value: "12%"},
{display: "30 years", value: "36%"}]
const items = selector
.selectAll('options')
.data(allMessages)
.enter()
.append('option')
.text(function (d) { return d.display; })
.attr("value", function (d) { return d.value; })
// set the default value by settings "selected", true for the item that matches the filter
items.filter(function(d) {return d.value === "Choose a time frame"})
.attr("selected",true);
// Create the div that will hold the output message.
// We use <p></p> instead of svg text, since it formats nicely.
let p = div
.append("p")
.text("How likely is an earthquake in the east bay? ");
// this function gets called when an option is chosen on the button
selector.on('change', function() {
const selectedText = d3.select('#dropdown1 option:checked').text();
const selectedValue = d3.select("#dropdown1").property("value") ;
p.text(
"There is approximately a " + selectedValue +
" chance that an earthquake of 6.7 magnitude or higher will occur in the next "
+ selectedText + ".")
});
return div.node();
}
Insert cell
Insert cell
Insert cell
{
let div = d3.create('div');
let selector = div.append('select');
const colorChoices = ["Choose a color", "yellow", "blue", "red", "green", "purple", "black"]
const items = selector
.selectAll('options')
.data(colorChoices)
.enter()
.append('option')
.text(function (d) { return d; })
.attr("value", function (d) { return d; })
items.filter(function(d) {return d.value === "Choose a color"})
.attr("selected",true);
let container = div
.append('svg')
.attr('width', 1000)
.attr('height', 100);

const pinkGroup = container
.append("g")
.attr("transform", () => "translate(" + 100 + "," + 40 + ")")
.attr("id", "pinkGroup")
.attr('fill', '#ff96ca')
pinkGroup.append("circle")
.attr("r", '20')
selector.on('change', function() {
pinkGroup.attr("fill", this.value);
});

return div.node();
}
Insert cell
Insert cell
d3 = require('d3@5')
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more