簡體   English   中英

D3 中是否有“軸相等”?

[英]Is there an "axis equal" in D3?

我正在使用 D3 和 Python 創建一些圖。 使用 Python 我可以使軸相等,如圖 1 所示:

在 Python 中使用 Axis Equal

我想使用 D3 在 SVG 中實現相同的效果。 請參考圖 2,沒有軸相等:

Javascript d3中沒有軸等於

我使用的軸比例如下:

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是相當低級的,它只是方法的集合,所以你幾乎所有的事情都必須手工完成......

好消息是,解決問題所需的只是一些數學運算來計算新的范圍。

作為介紹,由於這是一個標記的問題,因此“軸相等”是一些程序中使用的術語,例如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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM