gpt4 book ai didi

d3.js - 如何根据数据值将特定颜色应用于 D3.js map ?

转载 作者:行者123 更新时间:2023-12-05 00:52:31 25 4
gpt4 key购买 nike

我有一张美国县 map ,它应该以动画形式显示 14 天内各县的产水量。我需要以红色(小于 50 毫米)、绿色(大于 49 毫米且小于 100 毫米)和蓝色(大于 100 毫米)显示颜色。我改编自 Mike Bostock 和 Rich Donohue 的以下代码:

<style>
.county {
fill:steelblue;
stroke: #fff; /*White*/
stroke-width: .5px;
}

#play, #clock {
position: absolute;
/*top: 15px;*/
}

#play {
/*left: 15px;*/
left: 160px;
top: 140px;
}

#clock {
left: 220px;
top: 148px;
}
<button id="play">Play</button>
<span id="clock">Day</span>
<h1 style="text-align:center">14-Day Water Yield By County</h1>

<div id="svgDiv1" style="text-align:center">
<svg width="960" height="600" stroke-linejoin="round" stroke-linecap="round">
<defs>
<filter id="blur">
<feGaussianBlur stdDeviation="5"></feGaussianBlur>
</filter>
</defs>
</svg>
<script>

//globals
var width, height, projection, path, group, graticule, svg, defs, attributeArray = [], currentAttribute = 0, playing = false;

function init() {

setMap();
animateMap();

}

function setMap() {

svg = d3.select("svg");

defs = svg.select("defs");

path = d3.geoPath();

d3.json("/topo/us-10m.v1.json", function (error, us) {
if (error) throw error;

defs.append("path")
.attr("id", "nation")
.attr("d", path(topojson.feature(us, us.objects.counties)));

svg.append("use")
.attr("xlink:href", "#nation")
.attr("fill-opacity", 0.2)
.attr("filter", "url(#blur)");

svg.append("use")
.attr("xlink:href", "#nation")
.attr("fill", "#fff");

svg.append("path")
.attr("fill", "none")
.attr("stroke", "#777")
.attr("stroke-width", 0.70)
.attr("d", path(topojson.mesh(us, us.objects.counties, function (a, b) { return a !== b; })));
});

loadData(); // let's load our data next
}

function loadData() {
queue() // queue function loads all external data files asynchronously
.defer(d3.json, "/topo/us-10m.v1.json") // our geometries
.defer(d3.csv, "/data/wtryld.csv") // and associated data in csv file
.await(processData); // once all files are loaded, call the processData function passing the loaded objects as arguments
}

function processData(error, us, countyData) {
// function accepts any errors from the queue function as first argument, then
// each data object in the order of chained defer() methods above
if (error) throw error;

//Get values from geojson
var conus = topojson.feature(us, us.objects.counties); // store the path in variable for ease

//Get values from csv file
for (var i in conus.features) { // for each geometry object
for (var j in countyData) { // for each row in the CSV
if (conus.features[i].id == countyData[j].id) { // if they match
for (var k in countyData[i]) { // for each column in the a row within the CSV
if (k != 'id' && k != 'County') { // select only number of days as column headings
if (attributeArray.indexOf(k) == -1) {
attributeArray.push(k); // add new column headings to our array for later
}
conus.features[i].properties[k] = Number(countyData[j][k]) // add each CSV column key/value to geometry object
}
}
break; // stop looking through the CSV since we made our match
}
}
}
d3.select('#clock').html(attributeArray[currentAttribute]); // populate the clock initially with the current day
drawMap(conus); // let's mug the map now with our newly populated data object
}

//Sort function; can specify multiple columns to sort: propSort("STATE", "COUNTY");
function propSort(props) {
if (!props instanceof Array) props = props.split(",");
return function sort(a, b) {
var p;
a = a.properties;
b = b.properties;
for (var i = 0; i < props.length; i++) {
p = props[i];
if (typeof a[p] === "undefined") return -1;
if (a[p] < b[p]) return -1;
if (a[p] > b[p]) return 1;
}
return 0;
};
}

function drawMap(conus) {

svg.selectAll(".feature") // select country objects (which don't exist yet)
.data(conus.features) // bind data to these non-existent objects
.enter().append("path") // prepare data to be appended to paths
.attr("class", "county") // give them a class for styling and access later
.attr("id", function (d) { return d.properties.id; }, true) // give each a unique id for access later
.attr("d", path); // create them using the svg path generator defined above

var dataRange = getDataRange(); // get the min/max values from the current day's range of data values
d3.selectAll('.county') // select all the counties
.attr('fill-opacity', function (d) {
return getColor(d.properties[attributeArray[currentAttribute]], dataRange); // give them an opacity value based on their current value
});
}

function sequenceMap() {
var dataRange = getDataRange(); // get the min/max values from the current year's range of data values
d3.selectAll('.county').transition() //select all the counties and prepare for a transition to new values
.duration(300) // give it a smooth time period for the transition
.attr('fill-opacity', function (d) {
return getColor(d.properties[attributeArray[currentAttribute]], dataRange); // the end color value
})
}

function getColor(valueIn, valuesIn) {
// create a linear scale
var color = d3.scale.linear()
.domain([valuesIn[0], valuesIn[1]]) // input uses min and max values
.range([.3, 1]); // output for opacity between .3 and 1 %

return color(valueIn); // return that number to the caller
}

function getDataRange() {
// function loops through all the data values from the current data attribute
// and returns the min and max values

var min = Infinity, max = -Infinity;
d3.selectAll('.county')
.each(function (d, i) {
var currentValue = d.properties[attributeArray[currentAttribute]];
if (currentValue <= min && currentValue != -99 && currentValue != 'undefined') {
min = currentValue;
}
if (currentValue >= max && currentValue != -99 && currentValue != 'undefined') {
max = currentValue;
}
});
return [min, max];
}

function animateMap() {

var timer; // create timer object
d3.select('#play')
.on('click', function () { // when user clicks the play button
if (playing == false) { // if the map is currently playing
timer = setInterval(function () { // set a JS interval
if (currentAttribute < attributeArray.length - 1) {
currentAttribute += 1; // increment the current attribute counter
} else {
currentAttribute = 0; // or reset it to zero
}
sequenceMap(); // update the representation of the map
d3.select('#clock').html(attributeArray[currentAttribute]); // update the clock
}, 2000);

d3.select(this).html('Stop'); // change the button label to stop
playing = true; // change the status of the animation
} else { // else if is currently playing
clearInterval(timer); // stop the animation by clearing the interval
d3.select(this).html('Play'); // change the button label to play
playing = false; // change the status again
}
});
}


window.onload = init(); // magic starts here

上面的代码通过使用填充不透明度来应用“choropleth”颜色。只有深浅不一的钢蓝色。但我需要应用绿色、蓝色和红色。

感谢任何帮助。

最佳答案

无需使用 css 设置所有要素的颜色,然后将线性比例中的不透明度值应用于每个要素,您可以直接使用比例输出颜色(D3 比例范围接受颜色)。然后,不要设置填充不透明度,只需设置填充即可。

例如:

var color = d3.scale.linear()
.domain([0, 9])
.range(["blue", "green"]);

var svg = d3.select('body')
.append('svg')
.attr('width',500)
.attr('height',200);

svg.selectAll('rect')
.data(d3.range(10))
.enter()
.append('rect')
.attr('x',function(d,i) { return i * 40; })
.attr('y',30)
.attr('width',30)
.attr('height',30)
.attr('fill',function(d,i) { return color(i); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>


请确保您的 css 仍然没有指定钢蓝色。

您还可以使用十六进制颜色代码或指定多个步骤:

var color = d3.scale.linear()
.domain([0, 5, 9])
.range(["blue", "yellow", "green"]);

var svg = d3.select('body')
.append('svg')
.attr('width',500)
.attr('height',200);

svg.selectAll('rect')
.data(d3.range(10))
.enter()
.append('rect')
.attr('x',function(d,i) { return i * 40; })
.attr('y',30)
.attr('width',30)
.attr('height',30)
.attr('fill',function(d,i) { return color(i); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>


但是,如果您想要每个值的明确步骤,您可能需要一个阈值比例:

var color = d3.scale.threshold()
.domain([2, 5, 9])
.range(["blue","yellow","green","orange"]);

var svg = d3.select('body')
.append('svg')
.attr('width',500)
.attr('height',200);

svg.selectAll('rect')
.data(d3.range(10))
.enter()
.append('rect')
.attr('x',function(d,i) { return i * 40; })
.attr('y',30)
.attr('width',30)
.attr('height',30)
.attr('fill',function(d,i) { return color(i); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>


范围中比阈值尺度的域多一个元素。想象一个单一的阈值,它会有一个大于的值,一个小于的值。

关于d3.js - 如何根据数据值将特定颜色应用于 D3.js map ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42546344/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com