如何用Observable Plot在堆叠条形图中展示不同数据集?
问题描述
我尝试用Observable Plot制作一个收支对比堆叠条形图,目前仅能展示单个数据集,不确定如何在同一张图表中同时呈现两个不同数据集。需要实现以下效果:
- 支出(EXPENSES):X轴展示堆叠数值、分类名称及数值文本,条形右侧显示总计
- 收入(INCOME):格式与支出完全一致
- 两个条形仅显示带总计数值的单个刻度
- 计算并绘制收支差值(作为第三个条形)
参考效果图:
实现方案
1. 合并并预处理数据集
将收入、支出数据合并为一个数组,新增type字段标记数据类型("收入"/"支出"),同时给支出数值添加负号,方便在X轴左右两侧区分展示:
const data = [ {type: "收入", category: "薪资", value: 8000}, {type: "收入", category: "奖金", value: 2000}, {type: "支出", category: "房租", value: -3000}, {type: "支出", category: "餐饮", value: -1500} ];
2. 绘制基础堆叠条形
使用Plot的barY标记,通过y: "type"将收支分为两个纵向条目,x: "value"作为堆叠数值,fill: "category"区分不同分类:
Plot.plot({ y: {domain: ["收入", "支出"]}, marks: [ Plot.barY(data, {x: "value", y: "type", fill: "category", stack: "x"}) ] })
3. 添加分类名称与数值文本
用text标记添加分类名称和数值,通过stackX: "center"让文本居中显示在对应堆叠块内:
Plot.text(data, { x: "value", y: "type", text: d => `${d.category}: ${Math.abs(d.value)}`, stackX: "center", fill: "white" })
4. 展示总计刻度与文本
先计算收支总计,再用ruleX绘制总计线,text标记显示总计数值:
// 计算收支总计 const totals = [ {type: "收入", total: d3.sum(data.filter(d => d.type === "收入"), d => d.value)}, {type: "支出", total: Math.abs(d3.sum(data.filter(d => d.type === "支出"), d => d.value))} ]; // 添加总计线和文本到marks数组 Plot.ruleX(totals, {x: d => d.type === "收入" ? d.total : -d.total, y: "type", stroke: "black"}), Plot.text(totals, { x: d => d.type === "收入" ? d.total + 50 : -d.total - 150, y: "type", text: d => `总计: ${d.total}`, fill: "black" })
5. 绘制收支差值条形
计算收支差值后生成单独数据集,用barY和text标记绘制差值条形及文本:
// 计算差值 const incomeTotal = totals.find(d => d.type === "收入").total; const expenseTotal = totals.find(d => d.type === "支出").total; const difference = [{type: "收支差值", value: incomeTotal - expenseTotal}]; // 添加差值条形到marks数组 Plot.barY(difference, {x: "value", y: "type", fill: "green"}), Plot.text(difference, {x: "value", y: "type", text: d => `差值: ${d.value}`, stackX: "center", fill: "white"})
内容的提问来源于stack exchange,提问作者ALx
相关产品推荐
相关产品推荐

