Public
Edited
Mar 31, 2024
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const svg = d3
.create("svg")
.attr("width", 1000)
.attr("height", 200)

svg
.append("circle")
.attr("cx",100)
.attr("cy",100)
.attr("r",20)
.style("fill", "#69b3a2")
.append("title")
.text("Yo!")

return svg.node()
}
Insert cell
Insert cell
Insert cell
{
const svg = d3
.create("svg")
.attr("width", 1000)
.attr("height", 200)

const circles = svg
.append("circle")
.attr("cx",100)
.attr("cy",100)
.attr("r",20)
.style("fill", "#69b3a2")

const label = svg
.append("text")
.attr("display", "none")

circles
.on("mouseover", function(e, d){

const [xm, ym] = d3.pointer(e)

d3.select(this)
.transition()
.duration(200)
.style("opacity", 1)
.style("stroke", "white")
.style("stroke-width", "6px")

const labelText = "Yoyoyo!"

label
.attr("display", null)
.attr("font-size", 15)
.attr("font-weight", "bold")
.style("opacity", 1)
.attr("transform", `translate(${xm}, ${ym})`)
.attr("dx", 9)
.attr("dy", -7)
.text(d => labelText)

})
.on("mouseleave", function(e, d){

d3.select(this)
.transition()
.duration(200)
.style("stroke", "none")

label
.attr("display", "none")

})

return svg.node()
}
Insert cell
Insert cell
Insert cell
{
const svg = d3
.create("svg")
.attr("width", 1000)
.attr("height", 200)

const circles = svg
.append("circle")
.attr("cx",100)
.attr("cy",100)
.attr("r",20)
.style("fill", "#69b3a2")

const tooltip = svg.append("g").style("display", "none")

circles
.on("mouseover", function(e, d){

const [xm, ym] = d3.pointer(e)

d3.select(this)
.transition()
.duration(200)
.style("opacity", 1)
.style("stroke", "white")
.style("stroke-width", "6px")

// tooltip
tooltip
.transition()
.duration(200)
.style("display", null)
tooltip.attr("transform", `translate(${xm - 4},${ym + 3})`);

const path = tooltip.append("path")
.attr("fill", "white")
.attr("stroke", "black");

const textLabel = "Yoyoyoyoyoyo!"

const text = tooltip
.append("text")
.text(textLabel)

size(text, path)

})
.on("mouseleave", function(e, d){

d3.select(this)
.transition()
.duration(200)
.style("stroke", "none")

tooltip
.style("display", "none")

})

// Wraps the text with a callout path of the correct size, as measured in the page.
function size(text, path) {
const {x, y, width: w, height: h} = text.node().getBBox();
text.attr("transform", `translate(${-w / 2},${15 - y})`);
path.attr("d", `M${-w / 2 - 10}, 5H-5l5, -5l5, 5H${w / 2 + 10}v${h + 20}h-${w + 20}z`);
}

return svg.node()
}
Insert cell
Insert cell
Insert cell
data = FileAttachment("aapl@1.csv").csv()
Insert cell
chart = {

const width = 928
const height = 500

const margins = ({
top: 20,
right: 30,
bottom: 30,
left: 40
})

// Declare the x (horizontal position) scale.
const x = d3.scaleUtc(d3.extent(aapl, d => d.Date), [margins.left, width - margins.right])
const y = d3.scaleLinear([0, d3.max(aapl, d => d.Close)], [height - margins.bottom, margins.top])

const line = d3.line()
.x(d => x(d.Date))
.y(d => y(d.Close))

// Create the SVG container.
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height)
.attr("style", "max-width: 100%; height: auto; height: intrinsic; font: 10px sans-serif;")
.style("-webkit-tap-highlight-color", "transparent")
.style("overflow", "visible")
.on("pointerenter pointermove", pointermoved)
.on("pointerleave", pointerleft)
.on("touchstart", event => event.preventDefault());

// Add the x-axis.
svg.append("g")
.attr("transform", `translate(0,${height - margins.bottom})`)
.call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0));

// Add the y-axis, remove the domain line, add grid lines and a label.
svg.append("g")
.attr("transform", `translate(${margins.left},0)`)
.call(d3.axisLeft(y).ticks(height / 40))
.call(g => g.select(".domain").remove())
.call(g => g.selectAll(".tick line").clone()
.attr("x2", width - margins.left - margins.right)
.attr("stroke-opacity", 0.1))
.call(g => g.append("text")
.attr("x", -margins.left)
.attr("y", 10)
.attr("fill", "currentColor")
.attr("text-anchor", "start")
.text("↑ Daily Close ($)"));

// Append a path for the line.
svg.append("path")
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", line(aapl));

// Create the tooltip container.
const tooltip = svg.append("g");

function formatValue(value) {
return value.toLocaleString("en", {
style: "currency",
currency: "USD"
});
}
function formatDate(date) {
return date.toLocaleString("en", {
month: "short",
day: "numeric",
year: "numeric",
timeZone: "UTC"
});
}
// Add the event listeners that show or hide the tooltip.
const bisect = d3.bisector(d => d.Date).center;
function pointermoved(event) {
const i = bisect(aapl, x.invert(d3.pointer(event)[0]));
tooltip.style("display", null);
tooltip.attr("transform", `translate(${x(aapl[i].Date)},${y(aapl[i].Close)})`);

const path = tooltip.selectAll("path")
.data([,])
.join("path")
.attr("fill", "white")
.attr("stroke", "black");

const text = tooltip.selectAll("text")
.data([,])
.join("text")
.call(text => text
.selectAll("tspan")
.data([formatDate(aapl[i].Date), formatValue(aapl[i].Close)])
.join("tspan")
.attr("x", 0)
.attr("y", (_, i) => `${i * 1.1}em`)
.attr("font-weight", (_, i) => i ? null : "bold")
.text(d => d));

size(text, path);
}

function pointerleft() {
tooltip.style("display", "none");
}

// Wraps the text with a callout path of the correct size, as measured in the page.
function size(text, path) {
const {x, y, width: w, height: h} = text.node().getBBox();
text.attr("transform", `translate(${-w / 2},${15 - y})`);
path.attr("d", `M${-w / 2 - 10},5H-5l5,-5l5,5H${w / 2 + 10}v${h + 20}h-${w + 20}z`);
}

return svg.node();
}
Insert cell
Insert cell
Insert cell
import {toc} from "@jonfroehlich/collapsible-toc"
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