如何在条形图上绘制 x 轴值?
How to plot x axis values over bars?
我更改了 X 轴的属性以在图表的条形图上绘制它的值。但是在我放置代码的任何地方,值总是绘制在条形图之前(“后面”),因此我们看不到它。
//This part of the code is OUTSIDE of the update function (line 44 of the fiddle)
//append group to plot X axis
const xAxisGroup = g.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${HEIGHT})`)
//This part of the code is INSIDE the update function (line 92)
const xAxisCall = d3.axisBottom(x)
xAxisGroup.call(xAxisCall)
.selectAll("text")
.attr("x", "-5") // <<<--- I change this to 50
.attr("y", "10")
.attr("text-anchor", "end")
.attr("transform", "rotate(-45)") // <<<--- I changed this to -90
如何在条形图上绘制此值?
这是 original chart and this is the modified 的 fiddle。月份值可能落后...... :-/
在 SVG 中,稍后 绘制的任何内容都位于顶部。因此,只需在绘制矩形后附加 x 轴 <g>
元素。或者,提高它:
xAxisGroup.raise()
这是您的代码,其中包含该更改:
//set general margin, width and height values
const MARGIN = {
LEFT: 128,
RIGHT: 8,
TOP: 32,
BOTTOM: 128
}
const WIDTH = 400 - MARGIN.LEFT - MARGIN.RIGHT
const HEIGHT = 300 - MARGIN.TOP - MARGIN.BOTTOM
//append svg plot area into div chart area
const svg = d3.select("#chart-area").append("svg")
.attr("width", WIDTH + MARGIN.LEFT + MARGIN.RIGHT)
.attr("height", HEIGHT + MARGIN.TOP + MARGIN.BOTTOM)
//append group into svg
const g = svg.append("g")
.attr("transform", `translate(${MARGIN.LEFT}, ${MARGIN.TOP})`)
//X label
g.append("text")
.attr("class", "x axis-label")
.attr("x", WIDTH / 2)
.attr("y", HEIGHT + 60)
.attr("font-size", "20px")
.attr("text-anchor", "middle")
.text("Month")
//Y label
g.append("text")
.attr("class", "y axis-label")
.attr("x", -(HEIGHT / 2))
.attr("y", -60)
.attr("font-size", "20px")
.attr("text-anchor", "middle")
.attr("transform", "rotate(-90)")
.text("Value")
//set scale for X axis
const x = d3.scaleBand()
.range([0, WIDTH])
.paddingInner(0.3)
.paddingOuter(0.2)
//set scale for Y axis
const y = d3.scaleLinear()
.range([HEIGHT, 0])
//append group to plot X axis
const xAxisGroup = g.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${HEIGHT})`)
//append group to plot Y axis
const yAxisGroup = g.append("g")
.attr("class", "y axis")
//import data
d3.csv("https://raw.githubusercontent.com/dbahiense/sotabook/main/revenues.csv").then(data => {
//parse values
data.forEach(d => {
d.revenue = Number(d.revenue)
d.profit = Number(d.profit)
})
//listen drop-down lists and trigger update function on change
//state
d3.select("#state")
.on("change", function(event, d) {
update(data)
})
//round
d3.select("#round")
.on("change", function(event, d) {
update(data)
})
//plot chart on page first load
update(data)
})
// update chart function
function update(data) {
//drop-down list listened values
let state = d3.select("#state").property("value")
let round = d3.select("#round").property("value")
//filter data by drop-down list values
let filteredData = data.filter(function(d) {
return d.state == state & d.round == round
})
//set domains for X and Y axes
x.domain(filteredData.map(d => d.month))
y.domain([0, d3.max(filteredData, d => d.revenue)])
const xAxisCall = d3.axisBottom(x)
const yAxisCall = d3.axisLeft(y)
//.tickFormat(d => d + "m")
yAxisGroup.call(yAxisCall)
// JOIN new data with old elements.
const rects = g.selectAll("rect")
.data(filteredData)
// EXIT old elements not present in new data.
rects.exit().remove()
// UPDATE old elements present in new data.
rects
.attr("y", d => y(d.revenue))
.attr("x", (d) => x(d.month))
.attr("width", x.bandwidth)
.attr("height", d => HEIGHT - y(d.revenue))
// ENTER new elements present in new data.
rects.enter().append("rect")
.attr("y", d => y(d.revenue))
.attr("x", (d) => x(d.month))
.attr("width", x.bandwidth)
.attr("height", d => HEIGHT - y(d.revenue))
.attr("fill", "steelblue")
xAxisGroup.raise()
.call(xAxisCall)
.selectAll("text")
.attr("x", "50")
.attr("y", "10")
.attr("text-anchor", "end")
.attr("transform", "rotate(-90)")
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="">
<title>5.4</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<!-- Custom styling -->
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<!-- Bootstrap grid setup -->
<div class="container">
<div class="row">
<select id="state">
<option value="US">US</option>
<option value="EU">EU</option>
<option value="AS">AS</option>
</select>
<select id="round">
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
<div class="row">
<div id="chart-area"></div>
</div>
</div>
<!-- External JS libraries -->
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<!-- Custom JS below-->
</body>
</html>
我更改了 X 轴的属性以在图表的条形图上绘制它的值。但是在我放置代码的任何地方,值总是绘制在条形图之前(“后面”),因此我们看不到它。
//This part of the code is OUTSIDE of the update function (line 44 of the fiddle)
//append group to plot X axis
const xAxisGroup = g.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${HEIGHT})`)
//This part of the code is INSIDE the update function (line 92)
const xAxisCall = d3.axisBottom(x)
xAxisGroup.call(xAxisCall)
.selectAll("text")
.attr("x", "-5") // <<<--- I change this to 50
.attr("y", "10")
.attr("text-anchor", "end")
.attr("transform", "rotate(-45)") // <<<--- I changed this to -90
如何在条形图上绘制此值?
这是 original chart and this is the modified 的 fiddle。月份值可能落后...... :-/
在 SVG 中,稍后 绘制的任何内容都位于顶部。因此,只需在绘制矩形后附加 x 轴 <g>
元素。或者,提高它:
xAxisGroup.raise()
这是您的代码,其中包含该更改:
//set general margin, width and height values
const MARGIN = {
LEFT: 128,
RIGHT: 8,
TOP: 32,
BOTTOM: 128
}
const WIDTH = 400 - MARGIN.LEFT - MARGIN.RIGHT
const HEIGHT = 300 - MARGIN.TOP - MARGIN.BOTTOM
//append svg plot area into div chart area
const svg = d3.select("#chart-area").append("svg")
.attr("width", WIDTH + MARGIN.LEFT + MARGIN.RIGHT)
.attr("height", HEIGHT + MARGIN.TOP + MARGIN.BOTTOM)
//append group into svg
const g = svg.append("g")
.attr("transform", `translate(${MARGIN.LEFT}, ${MARGIN.TOP})`)
//X label
g.append("text")
.attr("class", "x axis-label")
.attr("x", WIDTH / 2)
.attr("y", HEIGHT + 60)
.attr("font-size", "20px")
.attr("text-anchor", "middle")
.text("Month")
//Y label
g.append("text")
.attr("class", "y axis-label")
.attr("x", -(HEIGHT / 2))
.attr("y", -60)
.attr("font-size", "20px")
.attr("text-anchor", "middle")
.attr("transform", "rotate(-90)")
.text("Value")
//set scale for X axis
const x = d3.scaleBand()
.range([0, WIDTH])
.paddingInner(0.3)
.paddingOuter(0.2)
//set scale for Y axis
const y = d3.scaleLinear()
.range([HEIGHT, 0])
//append group to plot X axis
const xAxisGroup = g.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${HEIGHT})`)
//append group to plot Y axis
const yAxisGroup = g.append("g")
.attr("class", "y axis")
//import data
d3.csv("https://raw.githubusercontent.com/dbahiense/sotabook/main/revenues.csv").then(data => {
//parse values
data.forEach(d => {
d.revenue = Number(d.revenue)
d.profit = Number(d.profit)
})
//listen drop-down lists and trigger update function on change
//state
d3.select("#state")
.on("change", function(event, d) {
update(data)
})
//round
d3.select("#round")
.on("change", function(event, d) {
update(data)
})
//plot chart on page first load
update(data)
})
// update chart function
function update(data) {
//drop-down list listened values
let state = d3.select("#state").property("value")
let round = d3.select("#round").property("value")
//filter data by drop-down list values
let filteredData = data.filter(function(d) {
return d.state == state & d.round == round
})
//set domains for X and Y axes
x.domain(filteredData.map(d => d.month))
y.domain([0, d3.max(filteredData, d => d.revenue)])
const xAxisCall = d3.axisBottom(x)
const yAxisCall = d3.axisLeft(y)
//.tickFormat(d => d + "m")
yAxisGroup.call(yAxisCall)
// JOIN new data with old elements.
const rects = g.selectAll("rect")
.data(filteredData)
// EXIT old elements not present in new data.
rects.exit().remove()
// UPDATE old elements present in new data.
rects
.attr("y", d => y(d.revenue))
.attr("x", (d) => x(d.month))
.attr("width", x.bandwidth)
.attr("height", d => HEIGHT - y(d.revenue))
// ENTER new elements present in new data.
rects.enter().append("rect")
.attr("y", d => y(d.revenue))
.attr("x", (d) => x(d.month))
.attr("width", x.bandwidth)
.attr("height", d => HEIGHT - y(d.revenue))
.attr("fill", "steelblue")
xAxisGroup.raise()
.call(xAxisCall)
.selectAll("text")
.attr("x", "50")
.attr("y", "10")
.attr("text-anchor", "end")
.attr("transform", "rotate(-90)")
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="">
<title>5.4</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<!-- Custom styling -->
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<!-- Bootstrap grid setup -->
<div class="container">
<div class="row">
<select id="state">
<option value="US">US</option>
<option value="EU">EU</option>
<option value="AS">AS</option>
</select>
<select id="round">
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
<div class="row">
<div id="chart-area"></div>
</div>
</div>
<!-- External JS libraries -->
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<!-- Custom JS below-->
</body>
</html>