gpt4 book ai didi

javascript - 使用 D3 创建多尺度、嵌套、顺序条形图

转载 作者:行者123 更新时间:2023-11-30 00:16:12 26 4
gpt4 key购买 nike

我正在制作 this infographic 的交互式版本

这在 D3 中被证明是困难的。会有多个序数尺度:

  • 每个国家/地区的 Y 尺度
  • 每个国家/地区每个时期的 Y 尺度
  • 一个X规模

对于每个周期,将有两个值(显示为两个不同颜色的条)。主要问题是并非所有国家都会有三个时期;数据的形状并不完全均匀。这就是说,第一个 Y 刻度的某些部分将具有不同的高度。我不确定如何处理这个问题。

假设我有这个数据:

CountryName Period  ValueA  ValueB
Argentina 2004-2008 12 5
Argentina 2004-2013 10 5
Argentina 2008-2013 8 4
Bolivia 2002-2008 4 2
Bolivia 2002-2013 6 18
Brazil 2003-2008 9 2
Brazil 2003-2013 2 19
Brazil 2008-2013 1 3

我使用 d3.nest() 函数:

d3.nest()
.key(function(d) { return d.CountryName; })
.key(function(d) { return d.Period; })
.map(data);

现在我将获得我想要的形式的数据,但请注意缺少一些数据 - 在这种情况下,玻利维亚只有两个时期的数据。我创建了一个 JSFiddle为此,但如您所见,它存在一些问题。条形的高度应该始终相同。我想使用 yScale.rangeBand(),但问题是有些国家会有三个时期,而有些国家只有两个时期。我还需要找到一种方法来在栏的左侧显示国家/地区名称和句点

如果有人有更好的方法来解决这个问题,请告诉我。我已经为此苦苦挣扎了几天。正如您从 JSFiddle 中看到的那样,我只有一个 yScale,但我确信根据我的情况最好使用两个 - 我不知道如何实现它。

非常感谢任何帮助

最佳答案

你可能真的不需要嵌套。这是一个特殊情况的条形图,因此您需要自己制作轴的条形刻度网格。

我在代码中添加了注释供您遵循

    var outerWidth = 1000;
var outerHeight = 500;
var margin = {
left: 100,
top: 0,
right: 100,
bottom: 90
};
var barPadding = 0.6;
var barPaddingOuter = 0.3;
var innerWidth = outerWidth - margin.left - margin.right;
var innerHeight = outerHeight - margin.top - margin.bottom;
//make your svg
var svg = d3.select("body").append("svg")
.attr("width", outerWidth)
.attr("height", outerHeight);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + 30 + ")");
//the axis is on the right
var xAxisG = g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + 10 + ")")

//the y axis is common for all
var yAxisG = g.append("g")
.attr("class", "y axis");

var xScale = d3.scale.linear().range([0, innerWidth]);
var yScale = d3.scale.ordinal().rangeRoundBands([0, innerHeight], barPadding, barPaddingOuter);

var yAxis = d3.svg.axis().scale(yScale).orient("left")
.outerTickSize(0);

function render(data) {
var xAxis = d3.svg.axis().scale(xScale).orient("top")
//.tickValues([-5, -4, -3, 0, 3, 5, 10, 15, 20, 25])
.outerTickSize(0)
.innerTickSize(-1 * outerHeight);

xScale.domain([0, 30]);

//this will make the y axis labels.
var country = "";
data.forEach(function(d) {
if (d.CountryName == country) {
d.label = d.Period
} else {
d.label = d.Period
d.heading = d.CountryName;
}
country = d.CountryName;
});
var labels = data.map(function(d) {
return d.label
});
//set the domain for all y labels,
yScale.domain(labels);
//makes the x Axis
xAxisG.call(xAxis);
//makes the y Axis
yAxisG.call(yAxis);
//make the bar chart for valueB
var bars = g.selectAll(".ValueA").data(data);
bars.enter().append("rect")
.attr("height", yScale.rangeBand() / 2);
bars
.attr("x", function(d) {
return xScale(0)
})
.attr("y", function(d) {
return yScale(d.label);
})
.attr("width", function(d) {
console.log(d.ValueA)
return xScale(d.ValueA);
})
.style("fill", "red")
.attr("class", "ValueA");
//make the bar chart for valueB
var bars = g.selectAll(".ValueB").data(data);
bars.enter().append("rect")
.attr("height", yScale.rangeBand() / 2);
bars
.attr("x", function(d) {
return xScale(0)
})
.attr("y", function(d) {
return yScale.rangeBand() / 2 + yScale(d.label);
})
.attr("width", function(d) {
return xScale(d.ValueB);
})
.style("fill", "blue")
.attr("class", "ValueA");
//make grid lines
var lines = g.selectAll(".xLine").data(data.filter(function(d){return !(d.heading == undefined) }));
lines.enter().append("line")
lines
.attr("x1", 0)
.attr("y1", function(d) {
return (yScale(d.label) - yScale.rangeBand())
})
.attr("x2", innerWidth)
.attr("y2", function(d) {
return (yScale(d.label) - yScale.rangeBand())
})
.style("stroke", "blue")
.attr("class", "xLine")
.style("display", function(s) {
if((yScale(s.label) - yScale.rangeBand()) < 0){
return "none";//not show grids when y comes negative
}
});

//make heading
var headings = g.selectAll(".heading").data(data.filter(function(d){return !(d.heading == undefined) }));
headings.enter().append("text")
.text(function(d){return d.heading})
.attr("x", -100)
.attr("y", function(d) {
return (yScale(d.label) - yScale.rangeBand()) +30
})

}

function type(d) {
d.ValueA = +d.ValueA;
d.ValueB = +d.ValueB;
console.log(d)
return d;
} d3.csv("https://gist.githubusercontent.com/cyrilcherian/e2dff83329af684cde78/raw/f85ce83497553c360d2af5d5dcf269390c44022f/cities.csv", type, render);
.tick line {
opacity: 0.2;
}

.xLine {
opacity: 0.2;
}

.axis text {
font-size: 10px;
}

.axis .label {}

.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}

.y.axis path,
.y.axis line {
stroke: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

希望这对您有所帮助!

关于javascript - 使用 D3 创建多尺度、嵌套、顺序条形图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34584864/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com