D3 path not showing - javascript

I am trying to make some features from a .geojson file render using D3 and D3geo and i am following this https://www.d3indepth.com/geographic/ as a guide. I don't really know what i am doing since i am not good at programing. It shows no errors on devtool console and when i inspect it in chrome it shows that the paths are created but the are not showing.
here is my code, the js part:
var width = Math.max(
document.documentElement.clientWidth,
window.innerWidth || 0
);
var height = Math.max(
document.documentElement.clientHeight,
window.innerHeight || 0
);
d3.json("2022.json").then(function (data) {
let geojson = data;
console.log(data);
let projection = d3
.geoMercator()
//.scale(1000)
//.center([20, 40])
//.translate([456, 250]);
projection.fitExtent([width, height], data);
let geoGenerator = d3.geoPath().projection(projection);
function update(geojson) {
let u = d3
.select("#content")
.data(geojson.features)
.enter()
u.append('path')
.join("path")
.attr("d", geoGenerator);
}
update(geojson);
});
enter image description here

Related

How can I define map extent based on points displayed?

I have the following map I've made, by overlaying points on a mapbox map using d3.js.
I'm trying to get the map to zoom so that the map extent just includes the d3 markers (points).
I think the pseudocode would look something like this:
//find the northernmost, easternmost, southernmost, westernmost points in the data
//get some sort of bounding box?
//make map extent the bounding box?
Existing code:
<div id="map"></div>
<script>
mapboxgl.accessToken = "YOUR_TOKEN";
var map = new mapboxgl.Map({
container: "map",
style: "mapbox://styles/mapbox/streets-v9",
center: [-74.5, 40.0],
zoom: 9
});
var container = map.getCanvasContainer();
var svg = d3
.select(container)
.append("svg")
.attr("width", "100%")
.attr("height", "500")
.style("position", "absolute")
.style("z-index", 2);
function project(d) {
return map.project(new mapboxgl.LngLat(d[0], d[1]));
}
#Lat, long, and value
var data = [
[-74.5, 40.05, 23],
[-74.45, 40.0, 56],
[-74.55, 40.0, 1],
[-74.85, 40.0, 500],
];
var dots = svg
.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("r", 20)
.style("fill", "#ff0000");
function render() {
dots
.attr("cx", function (d) {
return project(d).x;
})
.attr("cy", function (d) {
return project(d).y;
});
}
map.on("viewreset", render);
map.on("move", render);
map.on("moveend", render);
render(); // Call once to render
</script>
Update
I found this code for reference, linked here at https://data-map-d3.readthedocs.io/en/latest/steps/step_03.html:
function calculateScaleCenter(features) {
// Get the bounding box of the paths (in pixels!) and calculate a
// scale factor based on the size of the bounding box and the map
// size.
var bbox_path = path.bounds(features),
scale = 0.95 / Math.max(
(bbox_path[1][0] - bbox_path[0][0]) / width,
(bbox_path[1][1] - bbox_path[0][1]) / height
);
// Get the bounding box of the features (in map units!) and use it
// to calculate the center of the features.
var bbox_feature = d3.geo.bounds(features),
center = [
(bbox_feature[1][0] + bbox_feature[0][0]) / 2,
(bbox_feature[1][1] + bbox_feature[0][1]) / 2];
return {
'scale': scale,
'center': center
};
}
However, when I run the function:
var scaleCenter = calculateScaleCenter(data);
console.log("scalecenter is", scaleCenter)
I get the error:
path is not defined
Furthermore, it seems like I would need to dynamically adjust the center and zoom parameters of the mapbox map. Would I just set these values dynamically with the values produced by the calculateScaleCenter function?
The readthedocs example code is erroneously missing a bit of code
Your javascript code is reporting that you have not defined the variable path before using it. You have copied it correctly from readthedocs, but the code you are copying contains an omission.
Fortunately, on the readthedocs version of the code snippet, there is a mention of a Stack Overflow answer http://stackoverflow.com/a/17067379/841644
that gives more information.
Does adding this information, or something similar corresponding to your situation, help fix your problem?
var projection = d3.geo.mercator()
.scale(1);
var path = d3.geo.path()
.projection(projection);

Error displaying geotiff raster data on leaflet map

I hope someone can help me. I am trying to place isolines with labels from a geotiff file onto a leaflet map. The webpage https://geoexamples.com/d3-raster-tools-docs/plot/isolines.html is the example I am looking at, but the problem is that they perform this task on a non-moving leaflet map (no zoom feature). I have found the page https://bost.ocks.org/mike/leaflet/ where he places JSON data over a leaflet map, but does not cover how to transform geotiff data.
I can get the leaflet map to work and zoomable the JSON data remaps correctly but the geotiff data, while it displays, is not remapping correctly in my code and I don't quite understand how to make the isolines resize correctly. I thought it was taken care of with the svg.insert command but it doesn't. I know I am missing a step somewhere but I'm not sure where.
It seems like I am trying to do two things that are not quite explained anywhere combined. I eventually want to use the streamline code, too, which is why I am not using the XML code in the simple isolines code (and I need the labels). I got that version to work fine. I have also tried adding a canvas layer but that didn't work either, but perhaps I did something wrong with that.
I would greatly appreciate any suggestions on this. I think I have provided the necessary code and links to the files.
https://geoexamples.com/d3-raster-tools-docs/code_samples/tz850.tiff
https://geoexamples.com/d3-raster-tools-docs/code_samples/world-110m.json
var map = L.map('map').setView([-0.2858, 60.7868], 3);
mapLink =
'OpenStreetMap';
// Add an SVG element to Leaflet’s overlay pane
var svg = d3.select(map.getPanes().overlayPane).append("svg"),
g = svg.append("g").attr("class", "leaflet-zoom-hide");
d3.request("http://geoexamples.com/d3-raster-tools-docs/code_samples/tz850.tiff")
.responseType('arraybuffer')
.get(function(tiffData) {
d3.json("https://raw.githubusercontent.com/datasets/geo-countries/master/data/countries.geojson", function(geoShape) {
// create a d3.geo.path to convert GeoJSON to SVG
var transform = d3.geo.transform({
point: projectPoint
}),
path = d3.geo.path().projection(transform);
// create path elements for each of the features
d3_features = g.selectAll("path")
.data(geoShape.features)
.enter().append("path");
map.on("viewreset", reset);
reset();
// fit the SVG element to leaflet's map layer
function reset() {
bounds = path.bounds(geoShape);
var topLeft = bounds[0],
bottomRight = bounds[1];
svg.attr("width", bottomRight[0] - topLeft[0])
.attr("height", bottomRight[1] - topLeft[1])
.style("left", topLeft[0] + "px")
.style("top", topLeft[1] + "px");
g.attr("transform", "translate(" + -topLeft[0] + "," +
-topLeft[1] + ")");
// initialize the path data
d3_features.attr("d", path)
.style("fill-opacity", 0.7)
.attr('fill', 'blue');
}
// Use Leaflet to implement a D3 geometric transformation.
function projectPoint(x, y) {
var point = map.latLngToLayerPoint(new L.LatLng(y, x));
this.stream.point(point.x, point.y);
}
var tiff = GeoTIFF.parse(tiffData.response);
var image = tiff.getImage();
var rasters = image.readRasters();
var tiepoint = image.getTiePoints()[0];
var pixelScale = image.getFileDirectory().ModelPixelScale;
var geoTransform = [tiepoint.x, pixelScale[0], 0, tiepoint.y, 0, -1 * pixelScale[1]];
var zData = new Array(image.getHeight());
for (var j = 0; j < image.getHeight(); j++) {
zData[j] = new Array(image.getWidth());
for (var i = 0; i < image.getWidth(); i++) {
zData[j][i] = rasters[0][i + j * image.getWidth()];
}
}
var invGeoTransform = [-geoTransform[0] / geoTransform[1], 1 / geoTransform[1], 0, -geoTransform[3] / geoTransform[5], 0, 1 / geoTransform[5]];
var intervalsZ = [1400, 1420, 1440, 1460, 1480, 1500, 1520, 1540];
var linesZ = rastertools.isolines(zData, invGeoTransform, intervalsZ);
var colorScale = d3.scaleSequential(d3.interpolateYlOrRd)
.domain([1400, 1540]);
linesZ.features.forEach(function(d, i) {
svg.insert("path", ".streamline")
.datum(d)
.attr("d", path)
.style("stroke", colorScale(intervalsZ[i]))
.style("stroke-width", "2px")
.style("fill", "None");
});
})
})
<link rel="stylesheet" href="https://d19vzq90twjlae.cloudfront.net/leaflet-0.7/leaflet.css" />
<div id="map" style="width: 600px; height: 400px"></div>
<script src="http://bl.ocks.org/rveciana/raw/bef48021e38a77a520109d2088bff9eb/98a0b74b01109afae76d28bc27c4d1dbc7a87da8/geotiff.min.js"></script>
<script src="http://bl.ocks.org/rveciana/raw/bef48021e38a77a520109d2088bff9eb/98a0b74b01109afae76d28bc27c4d1dbc7a87da8/d3-marching-squares.min.js"></script>
<script src="http://bl.ocks.org/rveciana/raw/bef48021e38a77a520109d2088bff9eb/98a0b74b01109afae76d28bc27c4d1dbc7a87da8/path-properties.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d19vzq90twjlae.cloudfront.net/leaflet-0.7/leaflet.js">
</script>

Trouble appending d3 vectors to leaflet map

I'm trying to get points to overlay on a leaflet map.
I create the Map element in html, build the leaflet map, read in the data.
Here's where I'm getting tripped up. I'd like to display points on the map - I've already successfully displayed these points on a d3 map, but I want to re-display them on the above leaflet map. Rather then extract lat/longs, as I've seen in d3 + leaflet examples, I thought I'd just use the path generator function which I've used successfully before, in order to append points to leaflet.
Code sequence here:
<div id="map" class="sf" style="width: 600px; height: 400px"></div>
function ready(error) {
//Build Leaflet map
L.mapbox.accessToken =
'pk.eyJ1Ijoic3RhcnJtb3NzMSIsImEiOiJjaXFheXZ6ejkwMzdyZmxtNmUzcWFlbnNjIn0.IoKwNIJXoLuMHPuUXsXeug';
var mapboxUrl = 'https://api.mapbox.com/styles/v1/mapbox/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}';
//var accessToken = 'pk.eyJ1Ijoic3RhcnJtb3NzMSIsImEiOiJjam13ZHlxbXgwdncwM3FvMnJjeGVubjI5In0.-ridMV6bkkyNhbPfMJhVzw';
var map = L.map('map').setView([37.7701177, -122.40], 13);
mapLink =
'OpenStreetMap';
L.tileLayer(
'https://api.mapbox.com/styles/v1/mapbox/dark-v9/tiles/{z}/{x}/{y}?access_token=' + L.mapbox.accessToken, {
tileSize: 512,
zoomOffset: -1,
attribution: '© Mapbox © OpenStreetMap'
}).addTo(map);
// Read in the json data
d3.json("data/SanFrancisco_CoWorkingTenants.json",
function(SFData) {
var SFData = SFCoworking.features
console.log(SFData) // this prints successfully
})
var mapSVG = d3.select( "#map").select("svg")
mapG = mapSVG.append("g");
// Define d3 projection
var albersProjectionBay = d3.geoAlbers()
.scale( 282000)
.rotate ( [122.4077441,] )
.center( [0, 37.7701177] )
// Define d3 path
var geoPathBayArea = d3.geoPath()
.projection( albersProjectionBay );
var SFData = SFCoworking.features
console.log(SFData)
// draw points on map with d3 path generator
var feature = mapG.selectAll("path")
.data(SFCoworking.features)
.enter().append("path")
.style("stroke", "black")
.style("opacity", .6)
.style("fill", "red")
.attr("r", 20)
.attr( "d", geoPathBayArea )
console.log(feature) // nothing prints!
}
While the SFdata appears in the console, the features, when printed to the console, just appear as an empty array. This leads me to believe there might be an issue in how I'm appending the svg element to the map?
Thanks all - this seemed to work.
var svgLayer = L.svg();
svgLayer.addTo(map);
var svgMap = d3.select("#map").select("svg");
var g = svgMap.select('g');
d3.json("data/SanFrancisco_CoWorkingTenants.json", function(SFData) {
var SFData = SFCoworking.features
console.log(SFData)
})
SFData.forEach(function(d) {
d.latLong = new L.LatLng(d.properties.Latitude,
d.properties.Longitude);
//console.log(d.LatLng)
})
var feature = g.selectAll("circle")
.data(SFData)
.enter().append("circle")
.style("stroke", "black")
.style("opacity", .4)
.style("fill", "red")
.attr("r", 20)
.attr("class", 'features')

Updating several d3.js cartograms in the same container

I'm trying to update 4 cartograms in the same div.
First I create 4 original maps, each in its own svg, like this:
function makeMaps(data){
var mapsWrapper = d3.select('#maps');
data.forEach(function(topoJSON,i){
var quantize = d3.scale.quantize()
.domain([0, 1600000])
.range(d3.range(5).map(function(i) { return "q" + i; }));
var layer = Object.keys(topoJSON.objects)[0]
var svg = mapsWrapper.append('svg')
.attr("class","mapa")
.attr({
width: "350px",
height: "350px"
});
var muns = svg.append("g")
.attr("class", "muns")
.attr("id",layer)
.selectAll("path");
var geometry = topoJSON.objects[layer].geometries;
var carto = cartos[i]
var features = carto.features(topoJSON, geometry),
path = d3.geo.path()
.projection(projections[i]);
muns.data(features)
.enter()
.append("path")
.attr("class", function(d) {
return quantize(d.properties['POB1']);
})
.attr("d", path);
});
}
This part works well and creates 4 maps. After this, I want to update the paths in each map with the paths calculated by cartogram.js. The problem is that I can't get to the path data in each of the maps, here's what I'm trying to do:
...some code to calculate cartogram values
var cartograms = d3.selectAll(".mapa").selectAll("g").selectAll("path")
cartograms.forEach(function(region,i){
region.data(carto_features[i])
.select("title")
.text(function (d) {
return d.properties.nom_mun+ ': '+d.properties[year];
});
In cartograms I'm getting a nested selection: an array of paths for each map, which is what I though I needed, but inside the forEach I get the error region.data() is not a function. Each region is an array of paths each of which has a data property. I've tried with several ways of selecting the paths to no avail and I'm a little lost now. Thanks for your help

Error creating axis d3.js

I've been wrestling with this problem for quite a while now. I want to create an x-axis, so I used the following code:
var w = 1024,
h = 1024,
padding = 20,
fill = d3.scale.category20();
var vis = d3.select("#chart")
.append("svg:svg")
.attr("width", w)
.attr("height", h);
d3.json("force.json", function(json) {
//Create array of dates for the x-axis
var dates = json.nodes.map(function(d) {
return Date.parse(d.date);
});
console.log(dates)
// Create scale from the array of dates
var scale = d3.time.scale()
.domain(dates)
.range([padding, w - padding]);
console.log(scale(dates));
var axis = d3.svg.axis();
//more code below, but error gets called at the line above this comment.
}
However, I get the following error returned consistently:
Uncaught TypeError: Object #<Object> has no method 'axis'
This is very perplexing, as I was simply following the d3 API at https://github.com/mbostock/d3/wiki/SVG-Axes.
Would somebody kindly point out where I'm going wrong?
(for reference, force.json is the data I am working with)

Categories