我的城市是用错误的投影绘制的(非常小,在左边).使用d3.geo.albersUSA()



D3新手。

与正确大小的地图相比,我的城市是用错误的投影绘制的(非常小且在左边)。看起来经度也可能颠倒了。使用d3.geo.albersUSA () .

地图的比例设置为1000,地图看起来很棒。但我的数据并没有在相同的尺度上投射。

//Width and height of map (adding relative margins to see if that effects placement of circles. makes no apparent difference.)
var margin = { top: 0, left: 0, right: 0, bottom: 0},
height = 500 - margin.top - margin.bottom,
width = 960 - margin.left - margin.right;

// D3 Projection
var projection = d3.geo.albersUsa()
.translate([width/2, height/2])    // translate to center of screen
.scale([1000]);          // scale things down so see entire US

// Define path generator
var path = d3.geo.path()               // path generator that will convert GeoJSON to SVG paths
.projection(projection);  // tell path generator to use albersUsa projection

// Define linear scale for output
var color = d3.scale.linear()
.range(["rgb(165,110,255)","rgb(0,45,150)","rgb(0,157,154)","rgb(250,77,86)"]);
var legendText = ["High Demand, High Supply", "Low Demand, Low Supply", "Low Demand, High Supply", "High Demand, Low Supply"];
//Create SVG element and append map to the SVG
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);

// Append Div for tooltip to SVG
var div = d3.select("body")
.append("div")   
.attr("class", "tooltip")               
.style("opacity", 0);
// Load in my states data!
d3.csv("https://raw.githubusercontent.com/sjpozzuoli/Daves_Eagles/main/Data_Main/data_clusters_latlong_ready.csv", function(data) {
color.domain([0,1,2,3]); // setting the range of the input data
// Load GeoJSON data and merge with states data
d3.json("https://gist.githubusercontent.com/michellechandra/0b2ce4923dc9b5809922/raw/a476b9098ba0244718b496697c5b350460d32f99/us-states.json", function(json) {
// Loop through each state data value in the .csv file
for (var i = 0; i < data.length; i++) {
// Grab State Name
var dataState = data[i].state;
// Grab data value 
var dataValue = data[i].visited;
// Find the corresponding state inside the GeoJSON
for (var j = 0; j < json.features.length; j++)  {
var jsonState = json.features[j].properties.name;
if (dataState == jsonState) {
// Copy the data value into the JSON
json.features[j].properties.visited = dataValue; 
// Stop looking through the JSON
break;
}
}
}

// Bind the data to the SVG and create one path per GeoJSON feature
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.style("stroke", "#fff")
.style("stroke-width", "1")
.style("fill", function(d) {
// Get data value
var value = d.properties.visited;
if (value) {
//If value exists…
return color(value);
} else {
//If value is undefined…
return "rgb(213,222,217)";
}
});
//this piece of code brings in the data and reshapes it to numberic from string. Runs great. 
// Map the cities I have lived in!
d3.csv("https://raw.githubusercontent.com/sjpozzuoli/Daves_Eagles/main/Data_Main/data_clusters_latlong_ready.csv", function(data) {
var data;
data.forEach(function(d){
//create number values from strings
d.demand_score = +d.demand_score;
d.hotness_rank = +d.hotness_rank;
d.hotness_rank_yy = +d.hotness_rank_yy;
d.unique_viewers_per_property_yy =+ d.unique_viewers_per_property_yy;
d.median_days_on_market_yy =+ d.median_days_on_market_yy ;
d.median_listing_price_yy =+ d.median_listing_price_yy;
d.mortgage_rate =+ d.mortgage_rate;
d.supply_score =+ d.supply_score;
d.date = new Date(d.date);
d.latitude =+ d.latitude;
d.longitude =+ d.longitude;
d.class =+ d.class;
//console.log(d);
//console.log(d.city);
var city_state = d.city + ", " + d.state;
//console.log(city_state);
});
console.log(data, "data");
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
//dots are being drawn just with reverse longitude (neg?)and off the map
.attr("cx", function(d) {
var coords = ([d.longitude, d.latitude])
console.log("coords", coords)
//console.log(d.longitude, "d.longitude");
return coords[0];
})
.attr("cy", function(d) {
var coords = ([d.longitude, d.latitude])
return coords[1];
})

//size of circle working
.attr("r", function(d) {
return Math.sqrt(d.hotness_rank) * .05;
})
//todo: add if statement to correspond color with class 
.style("fill", "rgb(217,91,67)")    
.style("opacity", 0.85) 

美国在西半球,所以它的经度是负的,你所看到的行为是预期的,在这方面的数据是正确的。

问题是,您将经度和纬度视为像素坐标,而不是三维地球仪上的点。这就是它们出现在SVG左侧的原因。为了将地球仪上的点转换为笛卡尔象素,我们需要一个投影。

当您使用投影来投影美国的轮廓时(当您向路径生成器提供投影时),您不使用投影来投影您的点。无论何时使用多个地理数据源,您都需要确保投影的一致性,否则来自不同数据源的特征将不对齐。

解决方案很简单-用与轮廓相同的投影投影您的点:projection([longitude,latitude])将返回一个包含该点的投影x和y(以像素为单位)坐标的双元素数组:

.attr("cx", function(d) {
var coords = projection([d.longitude, d.latitude])
return coords[0];
})
.attr("cy", function(d) {
var coords = projection([d.longitude, d.latitude])
return coords[1];
})

下面是一个代码片段(为了演示和性能,将总循环数限制为3000):

//Width and height of map (adding relative margins to see if that effects placement of circles. makes no apparent difference.)
var margin = { top: 0, left: 0, right: 0, bottom: 0},
height = 500 - margin.top - margin.bottom,
width = 960 - margin.left - margin.right;

// D3 Projection
var projection = d3.geo.albersUsa()
.translate([width/2, height/2])    // translate to center of screen
.scale([1000]);          // scale things down so see entire US

// Define path generator
var path = d3.geo.path()               // path generator that will convert GeoJSON to SVG paths
.projection(projection);  // tell path generator to use albersUsa projection

// Define linear scale for output
var color = d3.scale.linear()
.range(["rgb(165,110,255)","rgb(0,45,150)","rgb(0,157,154)","rgb(250,77,86)"]);
var legendText = ["High Demand, High Supply", "Low Demand, Low Supply", "Low Demand, High Supply", "High Demand, Low Supply"];
//Create SVG element and append map to the SVG
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);

// Append Div for tooltip to SVG
var div = d3.select("body")
.append("div")   
.attr("class", "tooltip")               
.style("opacity", 0);
// Load in my states data!
d3.csv("https://raw.githubusercontent.com/sjpozzuoli/Daves_Eagles/main/Data_Main/data_clusters_latlong_ready.csv", function(data) {
color.domain([0,1,2,3]); // setting the range of the input data
// Load GeoJSON data and merge with states data
d3.json("https://gist.githubusercontent.com/michellechandra/0b2ce4923dc9b5809922/raw/a476b9098ba0244718b496697c5b350460d32f99/us-states.json", function(json) {
// Loop through each state data value in the .csv file
for (var i = 0; i < data.length; i++) {
// Grab State Name
var dataState = data[i].state;
// Grab data value 
var dataValue = data[i].visited;
// Find the corresponding state inside the GeoJSON
for (var j = 0; j < json.features.length; j++)  {
var jsonState = json.features[j].properties.name;
if (dataState == jsonState) {
// Copy the data value into the JSON
json.features[j].properties.visited = dataValue; 
// Stop looking through the JSON
break;
}
}
}

// Bind the data to the SVG and create one path per GeoJSON feature
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.style("stroke", "#fff")
.style("stroke-width", "1")
.style("fill", function(d) {
// Get data value
var value = d.properties.visited;
if (value) {
//If value exists…
return color(value);
} else {
//If value is undefined…
return "rgb(213,222,217)";
}
});
//this piece of code brings in the data and reshapes it to numberic from string. Runs great. 
// Map the cities I have lived in!
d3.csv("https://raw.githubusercontent.com/sjpozzuoli/Daves_Eagles/main/Data_Main/data_clusters_latlong_ready.csv", function(data) {
var data;
data.forEach(function(d){
//create number values from strings
d.demand_score = +d.demand_score;
d.hotness_rank = +d.hotness_rank;
d.hotness_rank_yy = +d.hotness_rank_yy;
d.unique_viewers_per_property_yy =+ d.unique_viewers_per_property_yy;
d.median_days_on_market_yy =+ d.median_days_on_market_yy ;
d.median_listing_price_yy =+ d.median_listing_price_yy;
d.mortgage_rate =+ d.mortgage_rate;
d.supply_score =+ d.supply_score;
d.date = new Date(d.date);
d.latitude =+ d.latitude;
// ensure longitue for US is negative:
d.longitude = d.longitude > 0 ? -d.longitude : + d.longitude;
d.class =+ d.class;
});

data = data.filter(function(d,i) {
return d.longitude && d.latitude && i++ < 3000;
})

svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) {
var coords = projection([d.longitude, d.latitude])

return coords[0]
})
.attr("cy", function(d) {

var coords = projection([d.longitude, d.latitude])
return coords[1];
})

//size of circle working
.attr("r", function(d) {
return Math.sqrt(d.hotness_rank) * .05;
})
//todo: add if statement to correspond color with class 
.style("fill", "rgb(217,91,67)")    
.style("opacity", 0.85) 

})
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>

最新更新