如何向 d3 中的轴添加文本标签?
例如,我有一个带有 x 轴和 y 轴的简单折线图。
在我的 x 轴上,我有从 1 到 10 的刻度。我希望“天”一词出现在其下方,以便人们知道 x 轴正在计算天数。
同样,在 y 轴上,我将数字 1-10 作为勾号,并且我希望“吃三明治”一词出现在侧面。
有没有简单的方法可以做到这一点?
轴标签未内置于 D3 的 axis 组件,但您只需添加 SVG
text
元素即可自行添加标签。一个很好的例子是我对 Gapminder 的动画气泡图的重新制作,国家的财富与健康。 x 轴标签如下所示:
svg.append("text")
.attr("class", "x label")
.attr("text-anchor", "end")
.attr("x", width)
.attr("y", height - 6)
.text("income per capita, inflation-adjusted (dollars)");
y 轴标签如下:
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("y", 6)
.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text("life expectancy (years)");
您还可以使用样式表根据需要设置这些标签的样式,可以一起 (
.label
) 或单独 (.x.label
、.y.label
)。
在新的 D3js 版本(版本 3 及以上)中,当您通过
d3.svg.axis()
函数创建图表轴时,您可以访问两个名为 tickValues
和 tickFormat
的方法,它们内置在函数内部,以便您可以指定您需要勾选哪些值以及您希望文本以什么格式显示:
var formatAxis = d3.format(" 0");
var axis = d3.svg.axis()
.scale(xScale)
.tickFormat(formatAxis)
.ticks(3)
.tickValues([100, 200, 300]) //specify an array here for values
.orient("bottom");
如果你想像我一样将 y 轴标签放在 y 轴中间:
-50
)chartHeight / 2
)代码示例:
var axisLabelX = -50;
var axisLabelY = chartHeight / 2;
chartArea
.append('g')
.attr('transform', 'translate(' + axisLabelX + ', ' + axisLabelY + ')')
.append('text')
.attr('text-anchor', 'middle')
.attr('transform', 'rotate(-90)')
.text('Y Axis Label')
;
这可以防止旋转整个坐标系,如上面 lubar 提到的。
如果您按照建议使用 d3.v4,您可以使用此实例来提供您需要的一切。
您可能只想用“天”替换 X 轴数据,但请记住正确解析字符串值而不是应用连接。
parseTime 也可以用日期格式来缩放天数?
d3.json("data.json", function(error, data) {
if (error) throw error;
data.forEach(function(d) {
d.year = parseTime(d.year);
d.value = +d.value;
});
x.domain(d3.extent(data, function(d) { return d.year; }));
y.domain([d3.min(data, function(d) { return d.value; }) / 1.005, d3.max(data, function(d) { return d.value; }) * 1.005]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y).ticks(6).tickFormat(function(d) { return parseInt(d / 1000) + "k"; }))
.append("text")
.attr("class", "axis-title")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.attr("fill", "#5D6971")
.text("Population)");
D3 提供了一组相当低级的组件,可用于组装图表。您将获得构建块、轴组件、数据连接、选择和 SVG。你的工作就是将它们组合在一起形成图表!
如果您想要一个传统的图表,即一对轴、轴标签、图表标题和绘图区域,为什么不看看d3fc?它是一组更高级的 D3 组件的开源集。它包括您可能需要的笛卡尔图表组件:
var chart = fc.chartSvgCartesian(
d3.scaleLinear(),
d3.scaleLinear()
)
.xLabel('Value')
.yLabel('Sine / Cosine')
.chartLabel('Sine and Cosine')
.yDomain(yExtent(data))
.xDomain(xExtent(data))
.plotArea(multi);
// render
d3.select('#sine')
.datum(data)
.call(chart);
您可以在此处查看更完整的示例:https://d3fc.io/examples/simple/index.html
chart.xAxis.axisLabel('Label here');
或
xAxis: {
axisLabel: 'Label here'
},
在 D3.js 中自定义轴
https://ghenshaw-work.medium.com/customizing-axes-in-d3-js-99d58863738b
let xAxisGenerator = d3.axisBottom(xScale);
let tickLabels = ['A','B','C'];
xAxisGenerator.tickFormat((d,i) => tickLabels[i]);
const svg = d3.select('#diagram');
const blockRadius = 30;
const ports = [
{ name: 'Port 1', position: 'top', offset: 0, portShape: 'circle', radius: 3 },
{ name: 'Port 2', position: 'right', offset: 0, portShape: 'rect', width: 6, height: 6 },
{ name: 'Port 3', position: 'bottom', offset: 0, portShape: 'filled-circle', radius: 5 },
{ name: 'Port 4', position: 'left', offset: 0, portShape: 'oval', rx: 5, ry: 3 }
]; // Example list of ports with positions, offsets, and shapes
// Create the circular block
svg.append('circle')
.attr('cx', 100)
.attr('cy', 100)
.attr('r', blockRadius)
.classed('block', true);
// Bind data to ports and create SVG shapes based on data
const portShapes = svg.selectAll('.port')
.data(ports)
.enter()
.append(d => {
if (d.portShape === 'circle' || d.portShape === 'filled-circle') {
return 'circle';
} else if (d.portShape === 'rect') {
return 'rect';
} else if (d.portShape === 'oval') {
return 'ellipse';
}
})
.attr('cx', d => {
let x;
switch (d.position) {
case 'top':
x = 100;
break;
case 'right':
x = 100 + blockRadius;
break;
case 'bottom':
x = 100;
break;
case 'left':
x = 100 - blockRadius;
break;
default:
x = 100;
}
return x;
})
.attr('cy', d => {
let y;
switch (d.position) {
case 'top':
y = 100 - blockRadius;
break;
case 'right':
y = 100;
break;
case 'bottom':
y = 100 + blockRadius;
break;
case 'left':
y = 100;
break;
default:
y = 100;
}
return y;
})
.attr('r', d => (d.portShape === 'circle' || d.portShape === 'filled-circle') ? d.radius : 0) // Radius based on shape
.attr('x', d => (d.portShape === 'rect') ? -d.width / 2 : d.position === 'right' ? blockRadius - d.width / 2 : d.position === 'left' ? -blockRadius - d.width / 2 : 0)
.attr('y', d => (d.portShape === 'rect') ? -d.height / 2 : d.position === 'top' ? -blockRadius - d.height / 2 : d.position === 'bottom' ? blockRadius - d.height / 2 : 0)
.attr('width', d => (d.portShape === 'rect') ? d.width : 0) // Width for rectangles
.attr('height', d => (d.portShape === 'rect') ? d.height : 0) // Height for rectangles
.classed('port', true);
// Add text labels for ports
svg.selectAll('.port-label')
.data(ports)
.enter()
.append('text')
.attr('x', d => {
let x;
switch (d.position) {
case 'top':
x = 100;
break;
case 'right':
x = 100 + blockRadius + 10;
break;
case 'bottom':
x = 100;
break;
case 'left':
x = 100 - blockRadius - 10;
break;
default:
x = 100;
}
return x;
})
.attr('y', d => {
let y;
switch (d.position) {
case 'top':
y = 100 - blockRadius - 10;
break;
case 'right':
y = 100;
break;
case 'bottom':
y = 100 + blockRadius + 10;
break;
case 'left':
y = 100;
break;
default:
y = 100;
}
return