Public
Edited
May 7, 2023
Insert cell
// md`# Final Assignment:

// Interactivity and Animation`
Insert cell
Insert cell
Insert cell
Insert cell
chart = DotPlot(conflictHelp, {
x: d => d.commitments,
y: d => d.country,
z: d => d.type,
// xFormat: "Bn",
// xLabel: "Help Amount % of GDP →",
width
});

Insert cell
// conflictHelp = FileAttachment("animation_data.csv").csv({typed: true})
conflictHelp = FileAttachment("country_data.csv").csv({typed: true})
Insert cell
chart.update(d3.groupSort(conflictHelp, D => order === "country" ? D[0].country : -D.find(d => d.type === order).commitments, d => d.country))
Insert cell
// Copyright 2021 Observable, Inc.
// Released under the ISC license.
// https://observablehq.com/@d3/dot-plot
// Adopted code from https://observablehq.com/@mbostock
// Adopted code from https://observablehq.com/@d3/dot-plot

function DotPlot(data, {
x = ([x]) => x, // given d in data, returns the (quantitative) value x
y = ([, y]) => y, // given d in data, returns the (categorical) value y
z = () => 1, // given d in data, returns the (categorical) value z
r = d => d.type === order ? (d.input === viewof order.input.value ? 16 : 8) : 8, // created by Ankita
xFormat, // a format specifier for the x-axis
marginTop = 70, // top margin, in pixels
marginRight = 30, // right margin, in pixels
marginBottom = 30, // bottom margin, in pixels
marginLeft = 250, // left margin, in pixels
width = 500, // outer width, in pixels
height = 600, // outer height, in pixels, defaults to heuristic
xType = d3.scaleLinear, // type of x-scale
xDomain, // [xmin, xmax]
xRange = [marginLeft, width - marginRight], // [left, right]
xLabel, // a label for the x-axis
yDomain, // an array of (ordinal) y-values
yRange, // [top, bottom]
yPadding = 1, // separation for first and last dots from axis
zDomain, // array of z-values
// colors = ["blue", "green", "red"], // color scheme
colors = ["#e377c2", "#3288bd", "#d62728", "White"], // color scheme
stroke = "currentColor", // stroke of rule connecting dots
strokeWidth, // stroke width of rule connecting dots
strokeLinecap, // stroke line cap of rule connecting dots
strokeOpacity, // stroke opacity of rule connecting dots
duration: initialDuration = 250, // duration of transition, if any
delay: initialDelay = (_, i) => i * 10, // delay of transition, if any
} = {}) {
// Compute values.
const X = d3.map(data, x);
const Y = d3.map(data, y);
const Z = d3.map(data, z);

// Compute default domains, and unique them as needed.
if (xDomain === undefined) xDomain = d3.extent(X);
if (yDomain === undefined) yDomain = Y;
if (zDomain === undefined) zDomain = Z;
yDomain = new d3.InternSet(yDomain);
zDomain = new d3.InternSet(zDomain);
// Omit any data not present in the y- and z-domains.
const I = d3.range(X.length).filter(i => yDomain.has(Y[i]) && zDomain.has(Z[i]));

// Compute the default height.
if (height === undefined) height = Math.ceil((yDomain.size + yPadding) * 16) + marginTop + marginBottom;
if (yRange === undefined) yRange = [marginTop, height - marginBottom];

// Construct scales and axes.
const xScale = xType(xDomain, xRange);
const yScale = d3.scalePoint(yDomain, yRange).round(true).padding(yPadding);
const color = d3.scaleOrdinal(zDomain, colors);
const xAxis = d3.axisTop(xScale).ticks(width / 80, xFormat);
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto; height: intrinsic; background-color: black;");
svg.append("g")
.attr("transform", `translate(0,${marginTop})`)
.call(xAxis)
.call(g => g.select(".domain").remove())
.call(g => g.selectAll(".tick line").clone()
.attr("y2", height - marginTop - marginBottom)
.attr("stroke-opacity", 0.15)
.attr("stroke", "white"))
.call(g => g.selectAll(".tick text") // Select all tick labels on the x-axis
.attr("fill", "white"))
.call(g => g.append("text")
.attr("x", width - marginRight)
.attr("y", -22)
.attr("fill", "currentColor")
// .attr("fill", "white")
.attr("text-anchor", "middle")
.text(xLabel));
// created by Ankita
const selectedInput = viewof order.input.value;
const displayType = ["Gross Domestic Product", "Monetary Commitments", "Refugee Support", "Total Support "];
const colorList = ["white","#e377c2", "#3288bd", "#d62728"]; // color list of text
const colorList1 = ["black","#e377c2", "#3288bd", "#d62728"]; // color list for circle

// created by Ankita
svg.append("text")
// .attr("x", 515 )
.attr("y", 25)
.attr("x", width/2 + 15 )
.attr("text-anchor", "center")
.attr("font-size", 20)
// .attr("font-family", "sans serif")
// .attr("text-anchor", "end")
// .attr("fill", "white")
.attr("fill", colorList[selectedInput])
.text(displayType[selectedInput])
svg.append("circle")
// .attr("cx", 500) // Center x-coordinate of the circle
.attr("cx", width/2 )
.attr("cy", 20) // Center y-coordinate of the circle
.attr("r", 10) // Radius of the circle
// .attr("fill", "blue") // Fill color of the circle
.attr("fill", colorList1[selectedInput])
// .text(displayType[selectedInput])

// created by Ankita
// svg.append("text")
// .attr("x", 5 )
// .attr("y", 35)
// .attr("text-anchor", "center")
// .attr("font-size", 30)
// // .attr("font-family", "sans serif")
// .attr("fill", "white")
// .text("Top 10 Countries Supporting Ukraine")
// svg.append("text")
// .attr("x", 5 )
// .attr("y", 60)
// .attr("text-anchor", "center")
// .attr("font-size", 15)
// // .attr("font-family", "sans serif")
// .attr("fill", "white")
// .text("The contributions have been normalized according to their respective proportions of the gross domestic product (GDP)")
// svg.append("text")
// .attr("x", 5 )
// .attr("y", 80)
// .attr("text-anchor", "center")
// .attr("font-size", 15)
// // .attr("font-family", "sans serif")
// .attr("fill", "#999999")
// .text("The countries change order based on the selected contribution type and GDP")

// Top 10 Countries Supporting Ukraine
// The contributions have been normalized according to their respective proportions of the gross domestic product (GDP)
// The countries change order based on the selected contribution type and GDP
// created by Ankita
svg.append("text")
.attr("x", width/2 )
.attr("y", height - 15)
.attr("text-anchor", "center")
.attr("font-size", 20)
.attr("fill", "white")
// .attr("font-family", "sans serif")
.text("Help Amount % of GDP →")

const g = svg.append("g")
.attr("text-anchor", "end")
.attr("font-family", "sans-serif")
.attr("font-size", 15)
.selectAll()
.data(d3.group(I, i => Y[i]))
.join("g")
.attr("transform", ([y]) => `translate(0,${yScale(y)})`);

g.append("line")
.attr("stroke", "gray")
.attr("stroke-width", strokeWidth)
.attr("stroke-linecap", strokeLinecap)
.attr("stroke-opacity", strokeOpacity)
.attr("x1", ([, I]) => xScale(d3.min(I, i => X[i])))
.attr("x2", ([, I]) => xScale(d3.max(I, i => X[i])));

// created by Ankita
g.selectAll("circle")
.data(([, I]) => I.filter(i => Z[i] !== "other"))
.join("circle")
.attr("cx", i => xScale(X[i]))
.attr("fill", i => color(Z[i]))
.attr("opacity", 1)
.attr("r", i => {
if (Z[i] === "total") {
return 10;
} else if (Z[i] === "refugee_help") {
return 7;
} else if (Z[i] === "commitments") {
return 7;
} else {
return 0;
}
});
// created by Ankita
g.append("text")
.attr("dy", "0.5em")
.attr("x", 160)
// .attr("fill", colorList[selectedInput])
.attr("fill", "white")
.text(([y]) => y);

return Object.assign(svg.node(), {
color,
update(yDomain, {
duration = initialDuration, // duration of transition
delay = initialDelay, // delay of transition
} = {}) {
yScale.domain(yDomain);
const t = g.transition().duration(duration).delay(delay);
t.attr("transform", ([y]) => `translate(0,${yScale(y)})`);
}
});
}
Insert cell
import {Legend} from "@d3/color-legend"
Insert cell
trigger = {
const input = viewof order.input;
const interval = setInterval(() => {
input.selectedIndex = (input.selectedIndex + 1) % input.length;
input.dispatchEvent(new Event("input", {bubbles: true}));
}, 5000);
const clear = () => clearInterval(interval);
input.addEventListener("change", clear, {once: true});
invalidation.then(() => (clear(), input.removeEventListener("change", clear)));
}
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