d3.js 画笔填充颜色直方图
Posted
技术标签:
【中文标题】d3.js 画笔填充颜色直方图【英文标题】:d3.js brush fill color histogram 【发布时间】:2016-12-11 15:16:47 【问题描述】:我用d3.js
创建了一些直方图。
我设法根据brush
的位置更改rect
的填充颜色。
但我想更改rect
内的颜色。例如,如果brush start
在rect
的中间,我想让我的rect
有两种颜色。
目前这就是我所拥有的:
这就是我想要的:
我见过一些例子,比如Here。我是 d3 的新手,我尝试理解代码。
我看到他们使用clip-path
,当他们没有画笔时肯定会隐藏背景栏,并根据画笔的范围显示它们。
这是JS Bin
更新
我已详细阅读了link 中提供的代码。我发现他们没有创建<rect>
元素来制作图表,但barPath
喜欢关注:
function barPath(groups)
var path = [],
i = -1,
n = groups.length,
d;
while (++i < n)
d = groups[i];
path.push("M", x(d.key), ",", height, "V", y(d.value), "h9V", height);
return path.join("");
但我不明白这个函数中发生了什么,以及如果他们没有其他方法可以做到这一点,如何以这种方式添加它。
【问题讨论】:
【参考方案1】:我不会尝试绘制部分条形(正如您的编辑似乎暗示的那样),而是将条形附加两次,一次是底部的灰色,然后是顶部的钢蓝。然后,您可以将剪辑路径应用于蓝色条,当它们被剪辑时,您会看到下面的灰色。
完整代码:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
<style>
.charts
padding: 10px 0;
.chart
padding-left: 20px;
padding-top: 10px;
.axis text
font: 10px sans-serif;
fill: black;
.chart text
font: 10px sans-serif;
fill: black;
.axis path,
.axis line
fill: none;
stroke: #000;
shape-rendering: crispEdges;
/*dont display yAxis for categorical variable*/
#chart .y.axis g
display: none;
/*Labels in categorical chart */
text#catTitle.catTitle
font: 10px sans-serif;
fill: white;
/*Color for the brush */
.brush rect.extent
fill: steelblue;
fill-opacity: .125;
/*Color for the brush resize path*/
.brush .resize path
fill: #eee;
stroke: #666;
/*Color for the hidden object*/
.hidden
fill: grey;
.bar
fill: steelblue;
</style>
</head>
<body>
<svg class="chart" id="chart"></svg>
<script>
var data = [
key: 1,
value: 37
,
key: 1.5,
value: 13
,
key: 2.5,
value: 1
,
key: 3,
value: 4
,
key: 3.5,
value: 14
,
key: 4,
value: 18
,
key: 4.5,
value: 21
,
key: 5,
value: 17
,
key: 5.5,
value: 16
,
key: 6,
value: 5
,
key: 6.5,
value: 4
];
var margin =
top: 10,
right: 41,
bottom: 42,
left: 10
;
var width = 400 - margin.left - margin.right,
height = 250 - margin.top - margin.bottom;
var y = d3.scale.linear()
.domain([0, d3.max(data, function(d)
return d.value
)])
.range([height, 0]);
var x = d3.scale.linear()
.domain([0, d3.max(data, function(d)
return d.key;
) + 1])
.rangeRound([0, width]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var chart = d3.select(".chart#chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("margin-left", 15 + "px");
chart.append("defs")
.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height);
var brush = d3.svg.brush()
.x(x)
.on("brush", brushed)
.on("brushend", brushend);
function brushend()
if (brush.empty())
chart.select("#clip>rect")
.attr("x", 0)
.attr("width", width);
function brushed()
var e = brush.extent();
chart.select("#clip>rect")
.attr("x", x(e[0]))
.attr("width", x(e[1]) - x(e[0]));
chart.selectAll(".hidden")
.data(data)
.enter().append("rect")
.attr("class", "hidden")
.attr("x", function(d)
return x(d.key);
)
.attr("y", function(d)
return y(d.value);
)
.attr("height", function(d)
return height - y(d.value);
)
.attr("width", x(0.5))
.style("stroke", "white")
.append("title")
.text(function(d)
return d.key;
);
chart.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("clip-path", "url(#clip)")
.attr("class", "bar")
.attr("x", function(d)
return x(d.key);
)
.attr("y", function(d)
return y(d.value);
)
.attr("height", function(d)
return height - y(d.value);
)
.attr("width", x(0.5))
.style("stroke", "white")
.append("title")
.text(function(d)
return d.key;
);
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
chart.append("text") //Add chart title
.attr("transform", "translate(" + (width / 2) + " ," + (height + margin.bottom) + ")")
.style("text-anchor", "middle")
.text("Petal Length");
chart.append("g")
.attr("class", "y axis")
.call(yAxis);
chart.append("g")
.attr("class", "x brush")
.call(brush) //call the brush function, causing it to create the rectangles
.selectAll("rect") //select all the just-created rectangles
.attr("y", -6)
.attr("height", (height + margin.top)) //set their height
function resizePath(d)
var e = +(d == "e"),
x = e ? 1 : -1,
y = height / 3;
return "M" + (.5 * x) + "," + y + "A6,6 0 0 " + e + " " + (6.5 * x) + "," + (y + 6) + "V" + (2 * y - 6) + "A6,6 0 0 " + e + " " + (.5 * x) + "," + (2 * y) + "Z" + "M" + (2.5 * x) + "," + (y + 8) + "V" + (2 * y - 8) + "M" + (4.5 * x) + "," + (y + 8) + "V" + (2 * y - 8);
chart.selectAll(".resize").append("path").attr("d", resizePath);
</script>
</body>
</html>
【讨论】:
【参考方案2】:对于希望将@Mark 的答案带到 v6 的任何人:
const data = [
key: 1,
value: 37
,
key: 1.5,
value: 13
,
key: 2.5,
value: 1
,
key: 3,
value: 4
,
key: 3.5,
value: 14
,
key: 4,
value: 18
,
key: 4.5,
value: 21
,
key: 5,
value: 17
,
key: 5.5,
value: 16
,
key: 6,
value: 5
,
key: 6.5,
value: 4
];
// svg sizes
const width = 400,
height = 200;
const m = 50;
const margin =
top: m,
right: m,
bottom: m,
left: m,
;
const y = d3.scaleLinear()
.domain(d3.extent(data, d => d.value))
.range([height - margin.bottom, margin.top]);
const x = d3.scaleLinear()
.domain(d3.extent(data, d => d.key).map((v, i) => i==0 ? v - 1 : v + 1))
.rangeRound([margin.left, width - margin.right]);
const svg = d3.select('svg')
.attr('width', width)
.attr('height', height)
.attr('viewBox', `0 0 $width $height`)
const rects = svg.append('g').attr('class', 'rects');
const clips = svg.append('g').attr('class', 'clips');
svg.append('g')
.attr('class', 'x-axis')
.attr('transform', `translate(0,$height - margin.bottom)`)
.call(d3.axisBottom(x));
svg.append('g')
.attr('class', 'y-axis')
.style('display', 'none')
.attr('transform', `translate($margin.left,0)`)
.call(d3.axisLeft(y));
svg.append('defs')
.append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('x', margin.left)
.attr('y', margin.top)
.attr('width', width - margin.right)
.attr('height', height - margin.bottom);
const brush = d3.brushX()
.extent([
[x.range()[0], margin.top],
[x.range()[1], height - margin.bottom]
])
.on('brush', brushed)
.on('start', brushed)
.on('end', brushend);
function brushend(e)
if (!e.selection || !e.selection.length)
svg.select('#clip>rect')
.attr('x', margin.left)
.attr('width', width - margin.right);
function brushed(e)
svg.select('#clip>rect')
.attr('x', e.selection[0])
.attr('width', e.selection[1] - e.selection[0]);
const selected =
x0: x.invert(e.selection[0]),
x1: x.invert(e.selection[1]),
rects.selectAll('rect')
.data(data)
.enter().append('rect')
.attr('x', d => x(d.key))
.attr('y', d => y(d.value))
.attr('height', d => height - y(d.value) - margin.bottom)
.attr('width', 20)
.style('stroke', 'white')
.style('fill', 'gray')
.append('title')
.text(d => d.key);
clips.selectAll('rect')
.data(data)
.enter().append('rect')
.attr('clip-path', 'url(#clip)')
.attr('x', d => x(d.key))
.attr('y', d => y(d.value))
.attr('height', d => height - y(d.value) - margin.bottom)
.attr('width', 20)
.style('stroke', 'white')
.append('title')
.text(d => d.key);
svg.append('g')
.attr('class', 'x brush')
.call(brush) // initialize the brush
.selectAll('rect')
.attr('y', 0)
.attr('height', height)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
<svg/>
【讨论】:
以上是关于d3.js 画笔填充颜色直方图的主要内容,如果未能解决你的问题,请参考以下文章