我正试图将这组数据(显示一个较大数据集的片段(链接到下方的图表照片
month_started Member_casual count_of_trides
7休闲435289
8件休闲407009
9成员385843
8名成员385305
7名成员373710
正如您所看到的,我有一个映射到成员或休闲属性的month_started。我想制作一个条形图,将month_started作为自变量(x(,将count_of_rides作为因变量(y(,每月将临时值叠加在成员的顶部。
我目前有一个d3条形图,它将month_started=7叠加在一起,而不是叠加在一起。我不知道如何让d3认识到它需要读取member_csual变量来分隔这两个值。
我有额外的代码,但这是我认为的相关部分
此外,我认为.data(bike_trips(应该是.data(stackedData(,但由于某种原因没有显示任何条形图,这让我认为我的错误可能是stakedData变量。
有人能告诉我正确的方向吗?
bike_trip_chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);
svg.append("g")
.attr("fill-opacity", .8)
.selectAll("rect")
.data(bike_trips)
.join("rect")
.attr("fill", (d) => colorScale(d.key))
.attr("x", d => x(d.month_started))
.attr("width", x.bandwidth())
.attr("y", d => y1(d.count_of_rides))
.attr("height", d => y1(0) - y1(d.count_of_rides));
svg.append("path")
.attr("fill", "none")
.attr("stroke", "#274e13")
.attr("stroke-miterlimit", 4)
.attr("stroke-width", 4)
.attr("d", line(chicago_weather));
svg.append("g")
.attr("fill", "none")
.attr("pointer-events", "all")
.selectAll("rect")
.data(bike_trips)
.join("rect")
.attr("x", d => x(d.month_started))
.attr("width", x.bandwidth())
.attr("y", 0)
.attr("height", height);
svg.append("g")
.call(xAxis);
svg.append("g")
.call(y1Axis);
svg.append("g")
.call(y2Axis);
return svg.node();
}
stackedData = d3.stack()
.keys(["member","casual"])
(bike_trips)
colorScale = d3.scaleOrdinal()
.domain(["member","casual"])
.range(["#E4BA14","#45818e"]);
在将数据传递给d3.stack()
之前,您希望它看起来像这样:
[
{month: 7, casual: 435289, member: 373710},
{month: 8, casual: 407009, member: 385305},
{month: 9, member: 385843}
]
下面是一个完整的例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://d3js.org/d3.v7.js"></script>
</head>
<body>
<div id="chart"></div>
<script>
// set up
const margin = { top: 25, right: 25, bottom: 50, left: 50 };
const width = 500 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;
const svg = d3.select('#chart')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// data
const data = [
{ month_started: 7, member_casual: "casual", count_of_rides: 435289 },
{ month_started: 8, member_casual: "casual", count_of_rides: 407009 },
{ month_started: 9, member_casual: "member", count_of_rides: 385843 },
{ month_started: 8, member_casual: "member", count_of_rides: 385305 },
{ month_started: 7, member_casual: "member", count_of_rides: 373710 },
];
const keys = ["member", "casual"];
const months = Array.from(new Set(data.map(d => d.month_started))).sort(d3.ascending);
// get a map from the month_started to the member_casual to the count_of_rides
const monthToTypeToCount = d3.rollup(
data,
// g is an array that contains a single element
// get the count for this element
g => g[0].count_of_rides,
// group by month first
d => d.month_started,
// then group by member of casual
d => d.member_casual
);
// put the data in the format mentioned above
const countsByMonth = Array.from(monthToTypeToCount, ([month, counts]) => {
// counts is a map from member_casual to count_of_rides
counts.set("month", month);
counts.set("total", d3.sum(counts.values()));
// turn the map into an object
return Object.fromEntries(counts);
});
const stackedData = d3.stack()
.keys(keys)
// return 0 if a month doesn't have a count for member/casual
.value((d, key) => d[key] ?? 0)
(countsByMonth);
// scales
const x = d3.scaleBand()
.domain(months)
.range([0, width])
.padding(0.25);
const y = d3.scaleLinear()
.domain([0, d3.max(countsByMonth, d => d.total)])
.range([height, 0]);
const color = d3.scaleOrdinal()
.domain(keys)
.range(["#E4BA14","#45818e"]);
// axes
const xAxis = d3.axisBottom(x);
svg.append('g')
.attr('transform', `translate(0,${height})`)
.call(xAxis)
const yAxis = d3.axisLeft(y);
svg.append('g')
.call(yAxis);
// draw bars
const groups = svg.append('g')
.selectAll('g')
.data(stackedData)
.join('g')
.attr('fill', d => color(d.key));
groups.selectAll('rect')
.data(d => d)
.join('rect')
.attr('x', d => x(d.data.month))
.attr('y', d => y(d[1]))
.attr('width', x.bandwidth())
.attr('height', d => y(d[0]) - y(d[1]));
// title
svg.append('g')
.attr('transform', `translate(${width / 2},${-10})`)
.attr('font-family', 'sans-serif')
.append('text')
.attr('text-anchor', 'middle')
.call(
text => text.append('tspan')
.attr('fill', color('member'))
.text('member')
)
.call(
text => text.append('tspan')
.attr('fill', 'black')
.text(' vs. ')
)
.call(
text => text.append('tspan')
.attr('fill', color('casual'))
.text('casual')
)
</script>
</body>
</html>