[英]Is there an "axis equal" in D3?
我正在使用 D3 和 Python 創建一些圖。 使用 Python 我可以使軸相等,如圖 1 所示:
我想使用 D3 在 SVG 中實現相同的效果。 請參考圖 2,沒有軸相等:
我使用的軸比例如下:
var xScale = d3.scaleLinear()
.range([0, width])
.domain([minX, maxX]);
var yScale = d3.scaleLinear()
.range([height, 0])
.domain([minY, maxY]);
var xAxis = d3.axisBottom(xScale).ticks(5),
yAxis = d3.axisLeft(yScale).ticks(5);
誰能告訴我如何實現與 D3 相等的軸?
簡短回答:不,D3 中沒有“軸相等” 。 D3是相當低級的,它只是方法的集合,所以你幾乎所有的事情都必須手工完成......
好消息是,解決問題所需的只是一些數學運算來計算新的范圍。
作為介紹,由於這是一個d3.js標記的問題,因此“軸相等”是一些程序中使用的術語,例如Matlab ,它...
對沿每個軸的數據單位使用相同的長度。
在視覺上可以更好地解釋它。 看看這張圖片,有不同的域和范圍( 來源):
在這個簡短的介紹之后,讓我們回到你的問題。 假設這個簡單的代碼,生成兩個軸:
const minX = 0, minY = 0, maxX = 120, maxY = 50, width = 500, height = 300, paddings = [10, 10, 20, 30]; const xScale = d3.scaleLinear() .range([paddings[3], width - paddings[1]]) .domain([minX, maxX]); const yScale = d3.scaleLinear() .range([height - paddings[2], paddings[0]]) .domain([minY, maxY]); const svg = d3.select("svg") .attr("width", width) .attr("height", height); svg.append("g") .attr("transform", `translate(0,${height - paddings[2]})`) .call(d3.axisBottom(xScale).tickSizeInner(-height + paddings[2] + paddings[0])); svg.append("g") .attr("transform", `translate(${paddings[3]},0)`) .call(d3.axisLeft(yScale).tickValues(xScale.ticks()).tickSizeInner(-width + paddings[3] + paddings[1]));
svg { border: 2px solid tan; } line { stroke-dasharray: 2, 2; stroke: gray; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <svg></svg>
正如我們可以清楚地看到的,這些單位不是等距的。 我們可以做兩件事來創建具有等距單位的軸:1. 更改域; 2. 更改范圍。
根據您的評論,更改域不是一種選擇。 因此,讓我們改為更改范圍。
我們所需要的只是計算每個用戶空間的單位數,並使用其中最大的(x 或 y)來改變相反比例的范圍。
例如,給定上面代碼片段的比例:
const xStep = Math.abs((xScale.domain()[1] - xScale.domain()[0]) / (xScale.range()[1] - xScale.range()[0]));
const yStep = Math.abs((yScale.domain()[1] - yScale.domain()[0]) / (yScale.range()[1] - yScale.range()[0]));
xStep
大於yStep
,向我們展示了 x 軸每個像素有更多的單位。 因此,我們將更改 y 軸范圍:
yScale.range([yScale.range()[0], yScale.range()[0] - (yScale.domain()[1] - yScale.domain()[0]) / xStep]);
這是演示:
const minX = 0, minY = 0, maxX = 120, maxY = 50, width = 500, height = 300, paddings = [10, 10, 20, 30]; const xScale = d3.scaleLinear() .range([paddings[3], width - paddings[1]]) .domain([minX, maxX]); const yScale = d3.scaleLinear() .range([height - paddings[2], paddings[0]]) .domain([minY, maxY]); const xStep = Math.abs((xScale.domain()[1] - xScale.domain()[0]) / (xScale.range()[1] - xScale.range()[0])); const yStep = Math.abs((yScale.domain()[1] - yScale.domain()[0]) / (yScale.range()[1] - yScale.range()[0])); yScale.range([yScale.range()[0], yScale.range()[0] - (yScale.domain()[1] - yScale.domain()[0]) / xStep]); const svg = d3.select("svg") .attr("width", width) .attr("height", height); svg.append("g") .attr("transform", `translate(0,${height - paddings[2]})`) .call(d3.axisBottom(xScale).tickSizeInner(-height + paddings[2] + yScale.range()[1])); svg.append("g") .attr("transform", `translate(${paddings[3]},0)`) .call(d3.axisLeft(yScale).tickValues(yScale.ticks().filter(function(d){return !(+d%10)})).tickSizeInner(-width + paddings[3] + paddings[1]));
svg { border: 2px solid tan; } line { stroke-dasharray: 2, 2; stroke: gray; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <svg></svg>
正如您使用網格線所看到的,單位現在等距。
最后,請記住,以編程方式確定將更改的比例、重新調整正確的范圍(例如,您的 y 比例從底部到頂部)、將軸居中等是完全不同的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.