英文:
How do I ensure D3 bar plot bars don't move away from their ticks while being responsive?
问题
我尝试在D3中创建一个条形图,显示负值和正值。我已经编写了代码来实现这个目标,但是我遇到了一个问题,矩形不正确地放置在x轴上。例如,1880年的矩形位于1880年刻度的右侧几个间隙。此外,代表2000年的条形图位于x轴上的1990年左右。理想情况下,我希望图表能够响应屏幕的空间,但确保条形图不会远离它们的刻度。
我曾假设.rangeBoundBands
会均匀分布它们,但看起来还有其他一些问题没有解决。非常感谢任何人可以提供的帮助。以下是您的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Land Ocean Temperature Index</title>
<!-- // <script type="text/javascript" src="../d3.v3.js"></script> -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<style type="text/css">
html, body, * {
font-family: Arial, sans-serif;
text-align: center;
font-size: 14px 65%;
}
.bar.positive {
fill: darkred;
}
.bar.negative {
fill: steelblue;
}
g.infowin {
fill: grey;
}
g.infowin text,
.axis text {
font: 11px sans-serif;
fill: grey;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
path.domain {
stroke: none;
}
</style>
</head>
<body>
<div id="chart"></div>
<script type="text/javascript">
var margin = {
top: 10,
right: 10,
bottom: 20,
left: 30
},
width = window.innerWidth - margin.left - margin.right,
height = window.innerHeight - margin.top - margin.bottom;
var y = d3.scale.linear()
.range([height, 0]);
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .2);
var xAxisScale = d3.scale.linear()
.domain([1880, 2015])
.range([0, width]);
var xAxis = d3.svg.axis()
.scale(xAxisScale)
.orient("bottom")
.tickFormat(d3.format("d"));
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var 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 + ")");
d3.csv("https://gist.githubusercontent.com/djr-taureau/d3599e17a3f1c5089a10e26dac9aee03/raw/a43e610d8b1c99bc17b8789b5641b84f243871b1/Land-Ocean-TempIndex-YR.csv", type, function(error, data) {
x.domain(data.map(function(d) {
return d.Year;
}));
y.domain(d3.extent(data, function(d) {
return d.Celsius;
})).nice();
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", function(d) {
if (d.Celsius < 0){
return "bar negative";
} else {
return "bar positive";
}
})
.attr("data-yr", function(d){
return d.Year;
})
.attr("data-c", function(d){
return d.Celsius;
})
.attr("title", function(d){
return (d.Year + ": " + d.Celsius + " °C")
})
.attr("y", function(d) {
if (d.Celsius > 0){
return y(d.Celsius);
} else {
return y(0);
}
})
.attr("x", function(d) {
return x(d.Year);
})
.attr("width", x.rangeBand())
.attr("height", function(d) {
return Math.abs(y(d.Celsius) - y(0));
})
.on("mouseover", function(d){
// alert("Year: " + d.Year + ": " + d.Celsius + " Celsius");
d3.select("#_yr")
.text("Year: " + d.Year);
d3.select("#degrree")
.text(d.Celsius + "°C");
});
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("g")
.attr("class", "y axis")
.append("text")
.text("°Celsius")
.attr("transform", "translate(15, 40), rotate(-90)")
svg.append("g")
.attr("class", "X axis")
.attr("transform", "translate(" + (margin.left - 6.5) + "," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "x axis")
.append("line")
.attr("y1", y(0))
.attr("y2", y(0))
.attr("x2", width);
svg.append("g")
.attr("class", "infowin")
.attr("transform", "translate(50, 5)")
.append("text")
.attr("id", "_yr");
svg.append("g")
.attr("class", "infowin")
.attr("transform", "translate(110, 5)")
.append("text")
.attr("id","degrree");
});
function type(d) {
d.Celsius = +d.Celsius;
return d;
}
</script>
</body>
</html>
如果您需要进一步的帮助或有其他问题,请随时告诉我。
英文:
I am trying to create a bar plot in D3 that displays negative and positive values. The code I have does this however I have an issue with the rectangle not sitting correctly on the x-Axis. For example the rectangle for the year 1880 sits a few spaces to the right of the 1880 tick. Also the bar representing 2000 sits around the 1990 mark on the x-Axis. Ideally I want the chart to be able to fill the space of the screen responsively but ensure the bars dont move away from their ticks.
I had assumed that .rangeBoundBands would space it out evenly but it looks like there is something else that's not quite working. Would really appreciate any help that anybody could offer. Code below:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Land Ocean Temperature Index</title>
<!-- // <script type="text/javascript" src="../d3.v3.js"></script> -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<style type="text/css">
html, body, * {
font-family: Arial, sans-serif;
text-align: center;
font-size: 14px 65%;
}
.bar.positive {
fill: darkred;
}
.bar.negative {
fill: steelblue;
}
g.infowin {
fill: grey;
}
g.infowin text,
.axis text {
font: 11px sans-serif;
fill:grey;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
path.domain {
stroke:none;
}
</style>
</head>
<body>
<div id="chart"></div>
<script type="text/javascript">
var margin = {
top: 10,
right: 10,
bottom: 20,
left: 30
},
width = window.innerWidth - margin.left - margin.right,
height = window.innerHeight - margin.top - margin.bottom;
var y = d3.scale.linear()
.range([height, 0]);
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .2);
var xAxisScale = d3.scale.linear()
.domain([1880, 2015])
.range([0, width]);
var xAxis = d3.svg.axis()
.scale(xAxisScale)
.orient("bottom")
.tickFormat(d3.format("d"));
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var 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 + ")");
d3.csv("https://gist.githubusercontent.com/djr-taureau/d3599e17a3f1c5089a10e26dac9aee03/raw/a43e610d8b1c99bc17b8789b5641b84f243871b1/Land-Ocean-TempIndex-YR.csv", type, function(error, data) {
x.domain(data.map(function(d) {
return d.Year;
}));
y.domain(d3.extent(data, function(d) {
return d.Celsius;
})).nice();
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", function(d) {
if (d.Celsius < 0){
return "bar negative";
} else {
return "bar positive";
}
})
.attr("data-yr", function(d){
return d.Year;
})
.attr("data-c", function(d){
return d.Celsius;
})
.attr("title", function(d){
return (d.Year + ": " + d.Celsius + " °C")
})
.attr("y", function(d) {
if (d.Celsius > 0){
return y(d.Celsius);
} else {
return y(0);
}
})
.attr("x", function(d) {
return x(d.Year);
})
.attr("width", x.rangeBand())
.attr("height", function(d) {
return Math.abs(y(d.Celsius) - y(0));
})
.on("mouseover", function(d){
// alert("Year: " + d.Year + ": " + d.Celsius + " Celsius");
d3.select("#_yr")
.text("Year: " + d.Year);
d3.select("#degrree")
.text(d.Celsius + "°C");
});
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("g")
.attr("class", "y axis")
.append("text")
.text("°Celsius")
.attr("transform", "translate(15, 40), rotate(-90)")
svg.append("g")
.attr("class", "X axis")
.attr("transform", "translate(" + (margin.left - 6.5) + "," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "x axis")
.append("line")
.attr("y1", y(0))
.attr("y2", y(0))
.attr("x2", width);
svg.append("g")
.attr("class", "infowin")
.attr("transform", "translate(50, 5)")
.append("text")
.attr("id", "_yr");
svg.append("g")
.attr("class", "infowin")
.attr("transform", "translate(110, 5)")
.append("text")
.attr("id","degrree");
});
function type(d) {
d.Celsius = +d.Celsius;
return d;
}
</script>
</body>
</html>
<!-- end snippet -->
答案1
得分: 1
将柱形图的中心对齐到刻度上,从柱形图的 x
坐标中减去其一半宽度:
attr("x", function(d) {
return x(d.Year) - x.rangeBand() / 2;
})
.attr("width", x.rangeBand())
英文:
To make center of a bar right on the tick, subtract its half-width from the bar's x
coordinate:
attr("x", function(d) {
return x(d.Year) - x.rangeBand() / 2;
})
.attr("width", x.rangeBand())
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论