javascript - 轴上重复的日期刻度
问题描述
我正在尝试在我的图表上显示一些日期/值配对,但 x 轴上有重复的值:
这是渲染刻度的代码:
chart
.select(".x-axis")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(xScale).ticks(data.length).tickFormat(d3.timeFormat("%y-%m")));
完整的代码片段:
var data = [{
date: "2020-01-01",
popularity: 50
},
{
date: "2020-02-01",
popularity: 150
},
{
date: "2020-03-01",
popularity: 200
},
{
date: "2020-04-01",
popularity: 250
},
{
date: "2020-05-01",
popularity: 200
},
{
date: "2020-06-01",
popularity: 250
},
{
date: "2020-07-01",
popularity: 350
}
];
// Create SVG and padding for the chart
const svg = d3
.select("#chart")
.append("svg")
.attr("height", 400)
.attr("width", 600);
const margin = {
top: 50,
bottom: 50,
left: 50,
right: 50
};
const chart = svg.append("g").attr("transform", `translate(${margin.left},0)`);
const width = +svg.attr("width") - margin.left - margin.right;
const height = +svg.attr("height") - margin.top - margin.bottom;
const grp = chart
.append("g")
.attr("transform", `translate(-${margin.left},-${margin.top})`);
// Add empty scales group for the scales to be attatched to on update
chart.append("g").attr("class", "x-axis");
chart.append("g").attr("class", "y-axis");
function updateScales(data) {
// Create scales
const yScale = d3
.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, dataPoint => dataPoint.popularity)]);
// Set Date Range
var earliestDate = new Date(data[0].date);
var lastDate = new Date(data[data.length - 1].date);
// Setting up date on the X axis
const xScale = d3
.scaleLinear()
.range([0, width])
.domain([earliestDate, lastDate]);
return {
yScale,
xScale
};
}
function updateAxes(data, chart, xScale, yScale) {
chart
.select(".x-axis")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(xScale).ticks(data.length).tickFormat(d3.timeFormat("%y-%m")));
chart
.select(".y-axis")
.attr("transform", `translate(0, 0)`)
.call(d3.axisLeft(yScale));
}
function updateChart(data) {
const {
yScale,
xScale
} = updateScales(data);
updateAxes(data, chart, xScale, yScale);
}
updateChart(data);
#chart {
text-align: center;
margin-top: 40px;
}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
</head>
<body>
<button>Update Chart</button>
<div id="chart"></div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.3.1/d3.js" integrity="sha512-CQk1Bd5qczb5n31LOjQ8nmasspRasRP95SzVXcjM2Crm+3pmP/evOvFqrHeR26IA6pkgraiKom0aGWF29d8xqQ==" crossorigin="anonymous"></script>
解决方案
.scaleTime()
与日期列表一起使用
var extent = d3.extent(data.map(_d=>new Date(_d.date)));
const xScale = d3.scaleTime().range([0, width])
.domain(extent);
var data = [{
date: "2020-01-01",
popularity: 50
},
{
date: "2020-02-01",
popularity: 150
},
{
date: "2020-03-01",
popularity: 200
},
{
date: "2020-04-01",
popularity: 250
},
{
date: "2020-05-01",
popularity: 200
},
{
date: "2020-06-01",
popularity: 250
},
{
date: "2020-07-01",
popularity: 350
}
];
// Create SVG and padding for the chart
const svg = d3
.select("#chart")
.append("svg")
.attr("height", 400)
.attr("width", 600);
const margin = {
top: 50,
bottom: 50,
left: 50,
right: 50
};
const chart = svg.append("g").attr("transform", `translate(${margin.left},0)`);
const width = +svg.attr("width") - margin.left - margin.right;
const height = +svg.attr("height") - margin.top - margin.bottom;
const grp = chart
.append("g")
.attr("transform", `translate(-${margin.left},-${margin.top})`);
// Add empty scales group for the scales to be attatched to on update
chart.append("g").attr("class", "x-axis");
chart.append("g").attr("class", "y-axis");
function updateScales(data) {
// Create scales
const yScale = d3
.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, dataPoint => dataPoint.popularity)]);
var extent = d3.extent(data.map(_d=>new Date(_d.date)));
// Setting up date on the X axis
const xScale = d3
.scaleTime()
.range([0, width])
.domain(extent);
return {
yScale,
xScale
};
}
function updateAxes(data, chart, xScale, yScale) {
chart
.select(".x-axis")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(xScale).ticks(data.length).tickFormat(d3.timeFormat("%y-%m")));
chart
.select(".y-axis")
.attr("transform", `translate(0, 0)`)
.call(d3.axisLeft(yScale));
}
function updateChart(data) {
const {
yScale,
xScale
} = updateScales(data);
updateAxes(data, chart, xScale, yScale);
}
updateChart(data);
#chart {
text-align: center;
margin-top: 40px;
}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
</head>
<body>
<button>Update Chart</button>
<div id="chart"></div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.3.1/d3.js" integrity="sha512-CQk1Bd5qczb5n31LOjQ8nmasspRasRP95SzVXcjM2Crm+3pmP/evOvFqrHeR26IA6pkgraiKom0aGWF29d8xqQ==" crossorigin="anonymous"></script>
推荐阅读
- swiftui - SwiftUI NavigationView 背景颜色
- python-3.x - 如何将字符串转换为 Python 中的字符列表?
- javascript - 在 Drupal 站点上不显示 Web 表单
- ruby - 请问如何在 RSPEC 上实现重试?
- stored-procedures - BigQuery 存储过程,用于捕获表名以及该表名的记录数
- reactjs - UseEffect 无限执行
- python - 在套接字传输中接收额外的字节
- machine-learning - 如何对每个样本的名义类别对象的无序列表进行编码以进行机器学习
- java - 为什么像 java.net.InetAddress 这样的 Java 类不记录任何内容?
- c++ - glCopyPixels() 没有返回选定的缓冲区像素