Public
Edited
May 21
Insert cell
Insert cell
chart = {
const barWidth = 30;
const marginTop = 30;
const marginRight = 10;
const marginBottom = 50;
const marginLeft = 40;
const width = alphabet.length * (barWidth + 10) + marginLeft + marginRight;
const height = 400;

// x scale: 分类轴
const x = d3.scaleBand()
.domain(alphabet.map(d => d.letter))
.range([marginLeft, width - marginRight])
.padding(0.2);

console.log("x domain:", x.domain());
console.log("x range:", x.range());

// y scale: 数值轴
const y = d3.scaleLinear()
.domain([0, d3.max(alphabet, d => d.frequency)])
.nice()
.range([height - marginBottom, marginTop]);

console.log("y domain:", y.domain());
console.log("y range:", y.range());

const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto; font: 12px sans-serif;");
// 创建圆角柱子的路径生成器
function roundedRect(x, y, width, height, radius) {
return [
["M", x + radius, y],
["L", x + width - radius, y],
["Q", x + width, y, x + width, y + radius],
["L", x + width, y + height],
["L", x, y + height],
["L", x, y + radius],
["Q", x, y, x + radius, y]
].map(d => d.join(" "));
}
// 添加柱子
svg.append("g")
.attr("fill", "steelblue")
.classed("selected", false)
.selectAll("rect")
.data(alphabet)
.join("rect")
.attr("x", d => x(d.letter))
.attr("y", d => y(d.frequency)) // 柱子顶部位置
.attr("width", x.bandwidth())
.attr("height", d => y(0) - y(d.frequency)) // 保证是正数
// .attr("rx", 5) // 圆角
// .attr("ry", 5) // 圆角
.each(function(d) {
console.log(`Drawing ${d.letter} at x=${x(d.letter)}, y=${y(d.frequency)}, height=${y(marginTop) - y(d.frequency)}`);
})
.on("click", function (event, d) {
// 移除之前的选中状态和动画
// 如果再次点击已选中的柱子,则恢复所有柱子
if (d3.select(this).classed("selected") === true) {
d3.selectAll("rect")
.classed("selected", false)
.transition()
.duration(300)
.style("opacity", 1);
} else {
d3.select(this)
.classed("selected", true)
.style("opacity", 1);
d3.selectAll("rect")
.filter(v => v !== d)
.classed("selected", false)
.transition()
.duration(300)
.style("opacity", 0.3);
}
// 设置当前柱子为选中
// 其他柱子淡出动画
// 其他柱子变透明
// d3.selectAll("rect")
// .filter(v => v !== d)
// .transition()
// .duration(500)
// .style("opacity", 0.3);
})
;

// 添加文本标签
svg.append("g")
.attr("fill", "black")
.attr("text-anchor", "middle")
.selectAll("text")
.data(alphabet)
.join("text")
.attr("x", d => x(d.letter) + x.bandwidth() / 2)
.attr("y", d => y(d.frequency) - 6)
.text(d => d3.format(".1%")(d.frequency));

// 添加底部 x 轴
svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom(x));

// 添加左侧 y 轴
svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(d3.axisLeft(y).ticks(height / 40, "%"));


svg.selectAll("rect")
.append("path")
.attr("d", d => roundedRect(
x(d.letter),
y(d.frequency),
x.bandwidth(),
height - y(d.frequency),
5 // 圆角半径
))
return svg.node();

function pointermoved(event) {
const [xm, ym] = d3.pointer(event);
// const i = d3.leastIndex(points, ([x, y]) => Math.hypot(x - xm, y - ym));
// const [x, y, k] = points[i];
// path.style("stroke", ({z}) => z === k ? null : "#ddd").filter(({z}) => z === k).raise();
// dot.attr("transform", `translate(${x},${y})`);
// dot.select("text").text(k);
// svg.property("value", unemployment[i]).dispatch("input", {bubbles: true});
}
}
Insert cell
alphabet = FileAttachment("alphabet.csv").csv({typed: true})
Insert cell
Insert cell
Plot.plot({
x: {axis: "top", percent: true},
y: {label: null},
marks: [
Plot.barX(alphabet, {x: "frequency", y: "letter", fill: "steelblue", sort: {y: "-x"}}),
Plot.text(alphabet, {x: "frequency", y: "letter", text: d => format(d.frequency), textAnchor: "start", dx: 3, filter: d => d.frequency <= 0.007, fill: "currentColor"}),
Plot.text(alphabet, {x: "frequency", y: "letter", text: d => format(d.frequency), textAnchor: "end", dx: -3, filter: d => d.frequency > 0.007, fill: "white" }),
Plot.ruleX([0])
]
})
Insert cell
format = d3.format(".1%")
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