- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在开发一个项目来绘制 csv/Json 数据流(条形图),其中数据的到达顺序很重要。Y 轴是唯一的,但有多个 X 轴对应于数据的不同度量。鉴于以下数据,我无法生成如下所示的漂亮图表:
x0,x1,x2,y,idx
-1,z,w2,10,0
0,z,w2,9,1
1,z,w2,8,2
-1,k,w2,11,3
0,k,5q,5,4
1,k,5q,8,5
这就是我得到的
X=["idx","x0","x1","x2"];
Y=["y"];
var margin = {
top: 80,
right: 180,
bottom: 180,
left: 180
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = [],
x = [];
var x_uid = d3.scale.ordinal()
.rangeRoundPoints([0, width]);
for (var idx = 0; idx < X.length; idx++) {
x[idx] = d3.scale.ordinal()
.rangeRoundPoints([0, width]);
xAxis[idx] = d3.svg.axis()
.scale(x[idx])
.orient("bottom");
}
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
// .ticks(8, "%");
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var data = [{
x0:-1,
x1:z,
x2:w2,
y:10,
idx:0
},
{
x0:0,
x1:z,
x2:w2,
y:10,
idx:1
},
{
x0:1,
x1:z,
x2:w2,
y:10,
idx:2
},
{
x0:-1,
x1:j,
x2:w2,
y:10,
idx:3
},
{
x0:0,
x1:j,
x2:5q,
y:10,
idx:4
},
{
x0:1,
x1:j,
x2:5q,
y:10,
idx:5
}]
if(data) {
for (var idx = 0; idx < X.length; idx++) {
x[idx].domain(data.map(function(d) {
return d[X[idx]];
}));
}
x_uid.domain(data.map(function(d) {
return d.idx;
}));
y.domain([0, d3.max(data, function(d) {
d.value = d[Y[0]];
return d.value;
})]);
for (var idx = 0; idx < X.length; idx++)
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height + idx * 25) + ")")
.call(xAxis[idx]);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x_uid(d.idx);
})
.attr("width", 1)
.attr("y", function(d) {
return y(d.value);
})
.attr("height", function(d) {
return height - y(d.value);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.6/d3.min.js"></script>
<div id="chart"></div>
偏移刻度线的文本不是问题,但由于值的多重性,我在插值方面遇到了问题: 例如w2 的宽度 > 5q 的宽度 例如x0 轴应为 -1 0 1 -1 0 1 但 d3 插值为 -1 0 1我尝试使用 rangeRoundBand 而不是 rangeRoundPoint 但问题类似。我也尝试过使用 tickValues 但无济于事。我尝试使用线性比例而不是序数进行自己的插值,但它很快就会变得非常困惑,因为这迫使我手动计算和调整所有刻度的位置和文本,同时考虑到 d3.behavior 缩放级别等...
function adjustTickPosition(selection, count, scale, translate, rotate) {
//selection = axis
//count = multiplicity of each tick
//scale = d3.behavior.zoom scale
//translate = d3.behavior.zoom translation
//rotate = irrelevent here (additional styling)
console.info( selection.selectAll("g.tick"))
// cancel previous position
//
// /!\ For some reason there is always 100 ticks instead of the appropriate number
//
selection.selectAll("g.tick")
.attr("transform", "translate(0,0)");
// align tick marks
selection.selectAll("g.tick line")
.attr('transform', function (d, k) {
if (k <= count.length - 1) {
var newPosition = scaleTranslate(count[k]);
if (newPosition > width || newPosition < 0) {
d3.select(this.parentNode).style("visibility", "hidden");
} else
d3.select(this.parentNode).style("visibility", "visible");
return 'translate(' + newPosition + ',0)';
} else
return 'translate(0,0)';
});
// offset tick label compared to tick marks
selection.selectAll("g.tick text")
.attr('transform', function (d, k) {
if (k <= count.length - 1) {
var pos, transform;
if (k > 0) pos = (count[k - 1] + count[k]) / 2;
else pos = count[k] / 2;
var newPosition = scaleTranslate(pos);
if (newPosition > width || newPosition < 0) {
d3.select(this.parentNode).style("visibility", "hidden");
} else
d3.select(this.parentNode).style("visibility", "visible");
var transform = 'translate(' + newPosition + ',0)';
if (rotate) transform += ' rotate(-65)';
return transform;
} else
return 'translate(0,0)';
});
if (rotate) selection.selectAll("g.tick text").style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em");
return selection;
function scaleTranslate(v) {
return v / count[count.length - 1] * width * scale + translate[0];
}
}
有人可以告诉我如何正确使用轴刻度来实现这种目的吗?
提前谢谢
最佳答案
我创建了自己的类/对象,因为 d3 显然不适用于这种图表
function chartAxis(key, args) {
//***************************
// PRIVATE
//***************************
var _direction = args ? (args.direction || "x") : "x";
var _width = args ? (args.width || 500) : 500;
var _alignTicks = args ? (args.alignTicks || false) : false;
var _tickSize = args ? (args.tickSize || 0) : 0;
var _numTicks = args ? (args.numTicks || 10) : 10;
var _offset = args ? (args.offset || 25) : 25;
var _zoom = args ? (args.zoom || {
s: 1,
t: 0
}) : {
s: 1,
t: 0
};
var _totalLength;
function consecutiveReduction(list, key) {
var Bin = function (val, cnt) {
return {
value: val,
count: cnt,
cumulativeCount: 0,
center: 0,
position: 0
};
};
var result = list.map(function (d) {
return key ? d[key] : d;
}).reduce(function (acc, d) {
var currentBin = acc[acc.length - 1];
if ((acc.length > 0) && d === currentBin.value) {
//add to current bin
currentBin.count++;
} else {
//create new bin
acc.push(new Bin(d, 1));
}
return acc;
}, []);
result.forEach(accumulate);
result.forEach(positionTick);
return result;
}
function positionTick(d) {
d.position = ApplyZoom(d.cumulativeCount);
d.center = _alignTicks ? d.position : ApplyZoom(d.cumulativeCount - d.count / 2);
function ApplyZoom(val) {
var translate;
if (_zoom.t.length > 1)
translate = (_direction == "x") ? _zoom.t[0] : _zoom.t[1];
else
translate = _zoom.t;
return val / _totalLength * _width * _zoom.s + translate;
}
}
function accumulate(d, i, arr) {
d.cumulativeCount = d.count;
if (i > 0) d.cumulativeCount += arr[i - 1].cumulativeCount;
}
//***************************
// PUBLIC
//***************************
var xAxis = function (selection) {
selection.each(function (data) {
// calculate
_totalLength = data.length;
var tickData = consecutiveReduction(data, key);
console.log(tickData.map(function (d) {
return d.count
}))
console.table(data,key)
//create parent axis with clip-path
var axis = d3.select(this)
.attr("id", key);
axis.selectAll("#clipAxis-" + key).data([1]).enter()
.append("clipPath")
.attr("id", "clipAxis-" + key)
.append("svg:rect")
.attr("x", 0)
.attr("y", _offset - _tickSize)
.attr("width", _width)
.attr("height", 25 + _tickSize);
// Axis line and label
var axisLine = axis.selectAll(".axisLine").data([1]).enter();
axisLine.append("line").attr({
x1: 0,
y1: _offset,
x2: _width,
y2: _offset,
class: "axisLine"
});
axisLine.append("text")
.text(key)
.attr({
x: _width + 10,
y: _offset
}).style("text-anchor", "start");
// tick on the axis
var ticks = axis.selectAll("g.tick")
.data(tickData);
// ENTER
var newticks = ticks.enter().append("g").attr("class", "tick");
newticks.append("line");
newticks.append("text");
// UPDATE
ticks.attr("clip-path", "url(#clipAxis-" + key + ")");
ticks.select(".tick line")
.attr("x1", function (d) {
return d.position
})
.attr("x2", function (d) {
return d.position
})
.attr("y1", function (d) {
return _offset - _tickSize
})
.attr("y2", function (d) {
return _offset + 5
});
ticks.select(".tick text")
.text(function (d) {
return d.value;
})
.attr("x", function (d) {
return d.center;
})
.attr("y", function (d) {
return _offset + 10;
})
.style("text-anchor", "middle")
.style("text-length", function (d) {
return (0.6 * 2 * (d.position - d.center)) + "px";
});
// EXIT
ticks.exit().remove();
})
};
var yAxis = function (selection) {
selection.each(function (data) {
// calculate
_totalLength = data.length;
var tickData = d3.extent(data, function (d) {
return d[key];
});
var tickRange = (tickData[1] - tickData[0]) / (_numTicks - 4 + 1); // -4 -> [0.85*min min ... max 1.15*max]
console.log(tickData.map(function (d) {
return d.count
}))
console.log(_tickSize)
//create parent axis with clip-path
var axis = axisLine = d3.select(this)
.attr("id", key);
axis.selectAll("#clipAxis-" + key).data([1]).enter()
.append("clipPath")
.attr("id", "clipAxis-" + key)
.append("svg:rect")
.attr("x", _offset)
.attr("y", 0)
.attr("width", _width)
.attr("height", 25 + _tickSize);
// Axis line and label
axisLine = axis.selectAll(".axisLine").data([1]).enter();
axisLine.append("line").attr({
x1: _offset,
y1: 0,
x2: _offset,
y2: _width,
class: "axisLine"
});
axisLine.append("text")
.text(key)
.attr({
x: _offset,
y: -10
}).style("text-anchor", "start");
// tick on the axis
var ticks = axis.selectAll("g.tick")
.data(tickData);
// ENTER
var newticks = ticks.enter().append("g").attr("class", "tick");
newticks.append("line");
newticks.append("text");
// UPDATE
ticks.attr("clip-path", "url(#clipAxis-" + key + ")");
ticks.select(".tick line")
.attr("x1", function (d) {
return _offset - 5
})
.attr("x2", function (d) {
return _offset + _tickSize
})
.attr("y1", function (d) {
return d.position
})
.attr("y2", function (d) {
return d.position
});
ticks.select(".tick text")
.text(function (d) {
return d.value;
})
.attr("x", function (d) {
return _offset + 10;
})
.attr("y", function (d) {
return d.center;
})
.style("text-anchor", "middle")
.style("text-length", function (d) {
return (0.6 * 2 * (d.position - d.center)) + "px";
});
// EXIT
ticks.exit().remove();
}); // end select.foreach
}; // end yAxis
xAxis.BindToZoom = function (zoomObject) {
_zoom = zoomObject;
return xAxis;
}
yAxis.BindToZoom = function (zoomObject) {
_zoom = zoomObject;
return yAxis;
}
return (_direction == "x") ? xAxis : yAxis;
}
用法:
function chartAxis(key, args) {
//***************************
// PRIVATE
//***************************
var _direction = args ? (args.direction || "x") : "x";
var _width = args ? (args.width || 500) : 500;
var _alignTicks = args ? (args.alignTicks || false) : false;
var _tickSize = args ? (args.tickSize || 0) : 0;
var _numTicks = args ? (args.numTicks || 10) : 10;
var _offset = args ? (args.offset || 25) : 25;
var _zoom = args ? (args.zoom || {
s: 1,
t: 0
}) : {
s: 1,
t: 0
};
var _totalLength;
function consecutiveReduction(list, key) {
var Bin = function(val, cnt) {
return {
value: val,
count: cnt,
cumulativeCount: 0,
center: 0,
position: 0
};
};
var result = list.map(function(d) {
return key ? d[key] : d;
}).reduce(function(acc, d) {
var currentBin = acc[acc.length - 1];
if ((acc.length > 0) && d === currentBin.value) {
//add to current bin
currentBin.count++;
} else {
//create new bin
acc.push(new Bin(d, 1));
}
return acc;
}, []);
result.forEach(accumulate);
result.forEach(positionTick);
return result;
}
function positionTick(d) {
d.position = ApplyZoom(d.cumulativeCount);
d.center = _alignTicks ? d.position : ApplyZoom(d.cumulativeCount - d.count / 2);
function ApplyZoom(val) {
var translate;
if (_zoom.t.length > 1)
translate = (_direction == "x") ? _zoom.t[0] : _zoom.t[1];
else
translate = _zoom.t;
return val / _totalLength * _width * _zoom.s + translate;
}
}
function accumulate(d, i, arr) {
d.cumulativeCount = d.count;
if (i > 0) d.cumulativeCount += arr[i - 1].cumulativeCount;
}
//***************************
// PUBLIC
//***************************
var xAxis = function(selection) {
selection.each(function(data) {
// calculate
_totalLength = data.length;
var tickData = consecutiveReduction(data, key);
//create parent axis with clip-path
var axis = d3.select(this)
.attr("id", key);
axis.selectAll("#clipAxis-" + key).data([1]).enter()
.append("clipPath")
.attr("id", "clipAxis-" + key)
.append("svg:rect")
.attr("x", 0)
.attr("y", _offset - _tickSize)
.attr("width", _width)
.attr("height", 25 + _tickSize);
// Axis line and label
var axisLine = axis.selectAll(".axisLine").data([1]).enter();
axisLine.append("line").attr({
x1: 0,
y1: _offset,
x2: _width,
y2: _offset,
class: "axisLine"
});
axisLine.append("text")
.text(key)
.attr({
x: _width + 10,
y: _offset
}).style("text-anchor", "start");
// tick on the axis
var ticks = axis.selectAll("g.tick")
.data(tickData);
// ENTER
var newticks = ticks.enter().append("g").attr("class", "tick");
newticks.append("line");
newticks.append("text");
// UPDATE
ticks.attr("clip-path", "url(#clipAxis-" + key + ")");
ticks.select(".tick line")
.attr("x1", function(d) {
return d.position
})
.attr("x2", function(d) {
return d.position
})
.attr("y1", function(d) {
return _offset - _tickSize
})
.attr("y2", function(d) {
return _offset + 5
});
ticks.select(".tick text")
.text(function(d) {
return d.value;
})
.attr("x", function(d) {
return d.center;
})
.attr("y", function(d) {
return _offset + 10;
})
.style("text-anchor", "middle")
.style("text-length", function(d) {
return (0.6 * 2 * (d.position - d.center)) + "px";
});
// EXIT
ticks.exit().remove();
})
};
var yAxis = function(selection) {
selection.each(function(data) {
// calculate
_totalLength = data.length;
var tickData = consecutiveReduction(data, key);
//create parent axis with clip-path
var axis = axisLine = d3.select(this)
.attr("id", key);
axis.selectAll("#clipAxis-" + key).data([1]).enter()
.append("clipPath")
.attr("id", "clipAxis-" + key)
.append("svg:rect")
.attr("x", _offset)
.attr("y", 0)
.attr("width", _width)
.attr("height", 25 + _tickSize);
// Axis line and label
axisLine = axis.selectAll(".axisLine").data([1]).enter();
axisLine.append("line").attr({
x1: _offset,
y1: 0,
x2: _offset,
y2: _width,
class: "axisLine"
});
axisLine.append("text")
.text(key)
.attr({
x: _offset,
y: -10
}).style("text-anchor", "start");
// tick on the axis
var ticks = axis.selectAll("g.tick")
.data(tickData);
// ENTER
var newticks = ticks.enter().append("g").attr("class", "tick");
newticks.append("line");
newticks.append("text");
// UPDATE
ticks.attr("clip-path", "url(#clipAxis-" + key + ")");
ticks.select(".tick line")
.attr("x1", function(d) {
return _offset - 5
})
.attr("x2", function(d) {
return _offset + _tickSize
})
.attr("y1", function(d) {
return d.position
})
.attr("y2", function(d) {
return d.position
});
ticks.select(".tick text")
.text(function(d) {
return d.value;
})
.attr("x", function(d) {
return _offset + 10;
})
.attr("y", function(d) {
return d.center;
})
.style("text-anchor", "middle")
.style("text-length", function(d) {
return (0.6 * 2 * (d.position - d.center)) + "px";
});
// EXIT
ticks.exit().remove();
}); // end select.foreach
}; // end yAxis
xAxis.BindToZoom = function(zoomObject) {
_zoom = zoomObject;
return xAxis;
}
yAxis.BindToZoom = function(zoomObject) {
_zoom = zoomObject;
return yAxis;
}
return (_direction == "x") ? xAxis : yAxis;
}
var data = [{
"a": 1,
"b": 3,
c: 1
}, {
"a": 1,
"b": 3,
c: 2
}, {
"a": 1,
"b": 2,
c: 3
}, {
"a": 1,
"b": 3,
c: 4
}, {
"a": 2,
"b": 3,
c: 5
}, {
"a": 3,
"b": "a",
c: 6
}, {
"a": 1,
"b": "a",
c: 7
}];
X = ["b", "a", "c"];
var axesDOM = d3.select("svg")
.selectAll(".axis")
.data(X).enter()
.append("g").attr("class", "axis");
axesDOM.each(function(x, i) {
d3.select(this).datum(data)
.call(new chartAxis(x, {
width: 200,
offset: 25 + i * 25,
direction: "x"
}));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="200px" height="200px"></svg>
关于javascript - D3 多轴插补,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32261147/
关闭。这个问题需要debugging details .它目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and th
我试图用这种形式简单地获取数字 28 integer+space+integer+integer+space+integer我试过这个正则表达式 \\s\\d\\d\\s 但我得到了两个数字11 和
最近一直在学习D语言。我一直对运行时感到困惑。 从我能收集到的关于它的信息中,(这不是很多)我知道它是一种有助于 D 的一些特性的运行时。像垃圾收集一样,它与您自己的程序一起运行。但是既然 D 是编译
想问一下这两个正则表达式有区别吗? \d\d\d 与 \d{3} 我已经在我的本地机器上使用 Java 和 Windows 操作系统对此进行了测试,两者都工作正常并且结果相同。但是,当在 linux
我正在学习 Go,而且我坚持使用 Go 之旅(exercise-stringer.go:https://tour.golang.org/methods/7)。 这是一些代码: type IPAddr
我在Java正则表达式中发现了一段令我困惑的代码: Pattern.compile( "J.*\\d[0-35-9]-\\d\\d-\\d\\d" ); 要编译的字符串是: String string
我在 ruby 代码上偶然发现了这个。我知道\d{4})\/(\d\d)\/(\d\d)\/(.*)/是什么意思,但是\1-\2-\3-\4 是什么意思? 最佳答案 \1-\2-\3-\4 是 b
我一直在努力解决这个问题,这让我很恼火。我了解 D 运行时库。它是什么,它做什么。我也明白你可以在没有它的情况下编译 D 应用程序。就像 XoMB 所做的那样。好吧,XoMB 定义了自己的运行时,但是
我有两个列表列表,子列表代表路径。我想找到所有路径。 List> pathList1 List> pathList2 当然是天真的解决方案: List> result = new ArrayList>
我需要使用 Regex 格式化一个字符串,该字符串包含数字、字母 a-z 和 A-Z,同时还包含破折号和空格。 从用户输入我有02-219 8 53 24 输出应该是022 198 53 24 我正在
目标是达到与this C++ example相同的效果: 避免创建临时文件。我曾尝试将 C++ 示例翻译为 D,但没有成功。我也尝试过不同的方法。 import std.datetime : benc
tl;dr:你好吗perfect forwarding在 D? 该链接有一个很好的解释,但例如,假设我有这个方法: void foo(T)(in int a, out int b, ref int c
有什么方法可以在 D 中使用abstract auto 函数吗? 如果我声明一个类如下: class MyClass { abstract auto foo(); } 我收到以下错误: mai
有没有人为内存中重叠的数组切片实现交集?算法在没有重叠时返回 []。 当 pretty-print (使用重叠缩进)内存中重叠的数组切片时,我想要这个。 最佳答案 如果您确定它们是数组,那么只需取 p
我已经开始学习 D,但我在使用 Andrei Alexandrescu 所著的 The D Programming Language 一书中提供的示例时遇到了一些麻烦。由于 int 和 ulong 类
如何创建一个不可变的类? 我的目标是创建一个实例始终不可变的类。现在我只是用不可变的方法和构造函数创建了一个“可变”类。我将其称为 mData,m 表示可变。然后我创建一个别名 alias immut
不久前我买了《The D Programming Language》。好书,很有教育意义。但是,我在尝试编译书中列出的语言功能时遇到了麻烦:扩展函数。 在这本书中,Andrei 写了任何可以像这样调用
我在 D http://www.digitalmars.com/d/2.0/lazy-evaluation.html 中找到了函数参数的惰性求值示例 我想知道如何在 D 中实现可能的无限数据结构,就像
这个问题在这里已经有了答案: 12 年前关闭。 Possible Duplicate: Could anyone explain these undefined behaviors (i = i++
当前是否可以跨模块扫描/查询/迭代具有某些属性的所有函数(或类)? 例如: source/packageA/something.d: @sillyWalk(10) void doSomething()
我是一名优秀的程序员,十分优秀!