javascript - 将面积图上的刻度线与字符串 X 值对齐
问题描述
我正在使用 D3 库构建面积图,并使用他们的面积图示例来帮助我构建它。但是,我没有沿 x 轴使用日期,而是使用字符串,因此我尝试使用他们的条形图示例来帮助我处理 xAxis 及其值。
但是,由于这个原因,我的 x 轴刻度线在两个值点之间“居中”,而不是左对齐(见下图)。
当我尝试使用面积图示例构建 xAxis 时,我没有看到任何被填充的区域或沿 xAxis 的任何数据点。
如何移动刻度线以直接在数据点上对齐,而不是在两个不同的数据点之间居中?
这是我的代码在构建图表时的样子”:
sampleAreaData = [
{"month": "Jun. 2018", "value": "2"},
{"month": "Jul. 2018", "value": "12"},
{"month": "Aug. 2018", "value": "33"},
{"month": "Sept. 2018", "value": "100"},
{"month": "Oct. 2018", "value": "150"},
{"month": "Nov. 2018", "value": "368"},
{"month": "Dec. 2018", "value": "404"},
{"month": "Jan. 2019", "value": "482"},
{"month": "Feb. 2019", "value": "559"},
]
initializeSampleAreaGraph() {
// Variables
const svg = d3.select(this.template.querySelector('svg.sampleAreaGraph'));
const width = this.svgSampleAreaWidth;
const height = this.svgSampleAreaHeight;
const margin = ({top: 20, right: 20, bottom: 30, left: 30});
const x = d3.scaleBand()
.domain(this.sampleAreaData.map(d => d.month))
.range([margin.left, width - margin.right])
const y = d3.scaleLinear()
.domain([0, d3.max(this.sampleAreaData, d => d.value)]).nice()
.range([height - margin.bottom, margin.top]);
const xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0));
const yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove())
.call(g => g.select(".tick:last-of-type text").clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(this.sampleAreaData.month));
const area = d3.area()
.x(d => x(d.month))
.y0(y(0))
.y1(d => y(d.value));
// SVG Construction
svg.append("path")
.attr("fill", "steelblue")
.datum(this.sampleAreaData)
.attr("d", area)
svg.append("g")
.call(xAxis);
svg.append("g")
.call(yAxis);
return svg.node();
}
解决方案
嗯,有几件事你可以改进。TL;博士; 下面的代码。
d3.scaleBand 将返回带中间的刻度,正如其名。以下图像是从d3 文档中无耻地复制的:
如您所见, scaleBand 的目的是将轴分成偶数带。
由于您已经拥有某种时间信息,您可以尝试解析它Date.parse(d.month)
并传递此信息来构建您的域。
我修改了您的代码段,使其在预览中有效,并评论了您的代码以进行其他一些改进。
var sampleAreaData = [
{"month": "Jun. 2018", "value": "2"},
{"month": "Jul. 2018", "value": "12"},
{"month": "Aug. 2018", "value": "33"},
{"month": "Sept. 2018", "value": "100"},
{"month": "Oct. 2018", "value": "150"},
{"month": "Nov. 2018", "value": "368"},
{"month": "Dec. 2018", "value": "404"},
{"month": "Jan. 2019", "value": "482"},
{"month": "Feb. 2019", "value": "559"},
];
function initializeSampleAreaGraph() {
// Variables
// const svg = d3.select(this.template.querySelector('svg.sampleAreaGraph')); // no need to select a selection. d3.select is the same as a querySelector.
const svg = d3.select('svg.sampleAreaGraph');
const width = 500;
const height = 500;
const margin = ({top: 20, right: 20, bottom: 30, left: 30});
const xScale = d3.scaleTime() // changed this to scaleBand
.domain(d3.extent(sampleAreaData, function(d) { return Date.parse(d.month) })) // d3.extent return an array with min and max values
.range([margin.left, width - margin.right]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(sampleAreaData, d => d.value)])
.nice()
.range([height - margin.bottom, margin.top]);
const xAxis = g => g
.attr("transform", `translate(0, ${height - margin.bottom})`)
.call(d3.axisBottom(xScale).ticks(width / 80).tickSizeOuter(0));
const yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(yScale))
.call(g => g.select(".domain").remove())
.call(g => g.select(".tick:last-of-type text").clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(sampleAreaData.month));
const area = d3.area(sampleAreaData)
.x(d => xScale(Date.parse(d.month))) // pass a valid date number
.y0(yScale(0))
.y1(d => yScale(d.value));
// SVG Construction
svg.append("path")
.attr("fill", "steelblue")
.datum(this.sampleAreaData)
.attr("d", area)
svg.append("g")
.call(xAxis);
svg.append("g")
.call(yAxis);
return svg.node();
}
initializeSampleAreaGraph();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="900" height="500" class="sampleAreaGraph"></svg>
我希望这有帮助。
推荐阅读
- python - Tkinter 列表框转到错误的功能
- haskell - Idris/cabal 在 Windows 上从 removePathRecursive 安装问题
- html - CSS - 图标的布局随着屏幕大小的变化从水平变为垂直
- kubernetes - Kubernetes:使用自定义资源更新 configMap
- html - IE中不显示背景图片
- java - 使用带有整数(索引)作为键的 HashMap 与使用 ArrayList
- android - Android模拟器在启动期间关闭
- javascript - 访问下拉列表的选定值时未定义
- python - 有什么方法可以比 for 循环更快地遍历数组吗?
- django - Django Python 在 html 中显示函数