当范围为0-1或0-2时,只显示d3.js中沿y轴的整个值 [英] Display only whole values along y axis in d3.js when range is 0-1 or 0-2
问题描述
我使用d3js来显示网站视图的实时表示。为此,我使用一个堆栈布局,我现在通过JSON更新我的数据集。
I am using d3js to display a realtime representation of the views of a website. For this I use a stack layout and I update my dataset by JSON at the moment.
当y轴上只显示1或2个视图时,动态与图中的视图量相关,轴标签为:1 => 0,0.2,0.4,0.6,0.8,1
,轴标签为:2 => 0,0.5,1,1.5,2
这对我的数据集没有意义,因为它显示页面的视图,而且不能有一半视图。
When there is only 1 or 2 views being displayed on the y axis, which is dynamic related to the amount of views in the graph, the axis labels are: 1 => 0, 0.2, 0.4, 0.6, 0.8, 1
, the axis labels are: 2 => 0, 0.5, 1, 1.5, 2
This makes no sense for my dataset since it displays views of a page, and you can't have half a view.
我在d3js中有一个线性尺度基于我的y轴
I have a linear scale in d3js I base my y axis on
var y_inverted = d3.scale.linear().domain([0, 1]).rangeRound([0, height]);
根据 rangeRound()的文档我应该只得到整个值。对于绘制我的轴,我使用:
According to the documentation of rangeRound() I should only get whole values out of this scale. For drawing my axis I use:
var y_axis = svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(0,0)")
.call(y_inverted.axis = d3.svg.axis()
.scale(y_inverted)
.orient("left")
.ticks(5));
因为它是一个实时应用程序,我每秒更新一次,通过调用:
Because it is a realtime application I update this every second by calling:
function update(){
y_inverted.domain([yStackMax, 0]);
y_axis.transition()
.duration(interval)
.ease("linear")
.call(y_inverted.axis);
}
yStackMax是从stacklayout计算的, y值只包含整数。
yStackMax is calculated from a stacklayout, as far as I know the data used for the y values only contain integers.
var yStackMax = d3.max(layers, function(layer) {
return d3.max(layer, function(d) {
return d.y0 + d.y;
});
});
我已经尝试过几个方法来为y轴获得正确的值。
I have tried several things to get a proper value for my y axis.
d3.svg.axis()
.scale(y_inverted)
.orient("left")
.ticks(5).tickFormat(d3.format(",.0f"))
最近的sofar,但仍显示 0,0,0,1,1,1
Got me the closest sofar, but it still displays 0, 0, 0, 1, 1, 1
只有当 yStackMax
为1时,才有1个tick,当它为2时为2个tick,但是如果 yStackMax
is 12 or 1,000,000
Basically what I want is to only have 1 tick when yStackMax
is 1, 2 ticks when it's 2, but it should also work if yStackMax
is 12 or 1,000,000
推荐答案
简短答案:您可以动态设置滴答数。将其设置为 1
,只显示两个刻度标签:
Short answer: You can dynamically set the number of ticks. Set it to 1
to display only two tick labels:
var maxTicks = 5, minTicks = 1;
if (yStackMax < maxTicks) {
y_axis.ticks(minTicks)
}
else {
y_axis.ticks(maxTicks)
}
长回答与你的例子我想出了一个相当完整的解决方案所有的格式化问题。随意使用它:)
Long Answer (going a bit off topic): While playing with your example I came up with a rather "complete solution" to all your formatting problems. Feel free to use it :)
var svg = d3.select("#svg")
var width = svg.attr("width")
var height = svg.attr("height")
var yStackMax = 100000
var interval = 500
var maxTicks = 5
var minTicks = 1
var y_inverted = d3.scale.linear().domain([0, 1]).rangeRound([0, height])
var defaultFormat = d3.format(",.0f")
var format = defaultFormat
var y_axis = d3.svg.axis()
.scale(y_inverted)
.orient("left")
.ticks(minTicks)
.tickFormat(doFormat)
var y_axis_root;
var decimals = 0;
function countDecimals(v){
var test = v, count = 0;
while(test > 10) {
test /= 10
count++;
}
return count;
}
function doFormat(d,i){
return format(d,i)
}
function init(){
y_axis_root = svg.append("g")
.attr("class", "y axis")
// I modified your example to move the axis to a visible part of the screen
.attr("transform", "translate(150,0)")
.call(y_axis)
}
// custom formatting functions:
function toTerra(d) { return (Math.round(d/10000000000)/100) + "T" }
function toGiga(d) { return (Math.round(d/10000000)/100) + "G" }
function toMega(d) { return (Math.round(d/10000)/100) + "M" }
function toKilo(d) { return (Math.round(d/10)/100) + "k" }
// the factor is just for testing and not needed if based on real world data
function update(factor){
factor = (factor) || 0.1;
yStackMax*=factor
decimals = countDecimals(yStackMax)
console.log("yStackMax decimals:",decimals, factor)
if (yStackMax < maxTicks) {
format = defaultFormat
y_axis.ticks(minTicks)
}
else {
y_axis.ticks(maxTicks)
if (decimals < 3 ) format = defaultFormat
else if(decimals < 6 ) format = toKilo
else if(decimals < 9 ) format = toMega
else if(decimals < 12) format = toGiga
else format = toTerra
}
y_inverted.domain([yStackMax, 0]);
y_axis_root.transition()
.duration(interval)
.ease("linear")
.call(y_axis);
}
init()
setTimeout(update, 200)
setTimeout(update, 400)
setTimeout(update, 600)
您可以与此html代码段一起试用:
You can try it together with this html snippet:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.v2.js"></script>
</head>
<body>
<div><svg id="svg" width="200" height="300"></svg></div>
<script src="axis.js"></script>
<button id="button1" onclick="update(10)">+</button>
<button id="button2" onclick="update(0.1)">-</button>
</body>
</html>
我知道这是一个有点偏离主题,但我通常喜欢提供运行的例子/解决方案。注意其他格式化内容作为实际问题的奖励。
I know it is a bit off topic but I usually like to provide running examples/solutions. Regard the additional formatting stuff as a bonus to the actual problem.
这篇关于当范围为0-1或0-2时,只显示d3.js中沿y轴的整个值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!