This question already has answers here:
D3.js Drawing geojson incorrectly
(2 answers)
Geojson map with D3 only rendering a single path in a feature collection
(3 answers)
Closed 2 years ago.
Currently I'm working a D3 project to render map with GeoJSON. I found this great example online https://bl.ocks.org/john-guerra/43c7656821069d00dcbc
and trying to implement with my GeoJSON map, while when I edited parameters according to new JSON file, the html only rendered partial map and showing in a rectangle. I tried to inspect the code but no clue where is wrong. Please share some hints where I can get the map display correctly. Full codes can be found on git https://github.com/gracemagy/singapore-map-D3
Thank you in advance!
Here is the code where I edited from original script:
updated targeted JSON file name
d3.json('electoral-boundary-dataset.geo.json', function(error, mapData) {
var features = mapData.features;
d.properties.NOMBRE_DPT to d.properties.Name
function nameFn(d){
return d && d.properties ? d.properties.Name : null;
}
scale(1500) to scale(50) to zoom out the map
var projection = d3.geo.mercator()
.scale(50)
Seems to me like there might be a problem with your geoJSON. It's like it has a frame around the map, and maybe that's the square you are looking at. If you make the fill of your example "none" and draw the stroke, you can see that your map is looking tiny inside this big square frame.
As #andrew-reid commented, this seems to be a winding problem. Check his comment on the original answer
Using the geoJSON from this bl.ock I was able to craft this example:
https://observablehq.com/d/21415ae86b8e5610
That doesn't have everything you want, but at least shows the map. Notice how it uses a projection that fits everything into the width and height
var projection = d3.geoMercator().fitSize([width, height], geoJSON);
Also, try not to use d3.v3, that's way too old.
Here is a working version:
https://observablehq.com/#john-guerra/geojson-singapur
Related
I am practicing on a simple weather app using OWM. I am fetching the coordinates and pass them to a function to display a map using leaflet.
Here is my code
function drawMap(lat,lon){
const mymap = L.map('map').setView([lat, lon],3);
L.tileLayer(`https://tile.openweathermap.org/map/temp_new/3/1/1.png?appid=${apiKey}`).addTo(mymap);
}
My issues are :
-Zoom level is required by leaflet but it's also in the openweather URL so i don't know if i need to put the same or not
-in the url, i'm supposed to put x and y tile coordinates , I don't really understand the required X and Y values and the OWM API doc doesn't really elaborate on those.
Right now , using the values 3/6/1 for example, i get
The zoom is just the same tiles over and over and you can't make out anything so obviously I'm doing something wrong
Thanks
I don't really understand what you are describing but normaly you would set template strings in the Tile-Url that can are replaced by leaflet:
L.tileLayer(`https://tile.openweathermap.org/map/temp_new/{z}/{x}/{y}.png?appid=${apiKey}`).addTo(mymap);
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
is it possible to use leaflet to move tile layer based on a offset
The problem is that I use OSM data to display markers and building outlines on the map but since am using another Tile Provider the OSM data is not sync with satellite image
Is there a simple way of adding offset in leaflet?
attached a screenshoot from openstreetmap's iD editor :
https://youtu.be/IRLyMKVERvo
Is it possible to use leaflet to move tile layer based on a offset?
Yes.
Is there a simple way of adding offset in leaflet?
No.
There are several approaches to offsetting a Leaflet L.TileLayer, but they're not straight forward. I would advise reading about extending Leaflet classes and reading Leaflet's source code before undertaking such a task.
One approach would be to use a decorator pattern on the specific bit of code that calculates the CSS offset of tiles, i.e. the internal _getTilePos() method of L.GridLayer:
_getTilePos: function (coords) {
return coords.scaleBy(this.getTileSize()).subtract(this._level.origin);
},
That internal method takes in the tile coordinates, and returns the pixel coordinates relative to what Leaflet calls the origin pixel. Those concepts are documented.
So I can create a decorator by subclassing L.TileLayer and creating a new class with a new implementation for _getTilePos (but reusing the implementation of the parent class), e.g.
var OffsetTileLayer = L.TileLayer.extend({
_getTilePos: function (coords) {
var pos = L.TileLayer.prototype._getTilePos.call(this, coords);
return pos.add([25, 25]);
},
});
var offsetTileLayer = new OffsetTileLayer(/* etc */);
offsetTileLayer.addTo(map);
See a working example.
That will offset the CSS position of tiles (which is represented by an instance of L.Point) by 25 horizontal and vertical pixels. Note that the offset is CSS pixels; not meters and not degrees of latitude/longitude.
It would be possible to make that offset depend on the tile coordinates (from which the latitude, longitude and scale can be derived), but I suspect that there would be artefacts (such as gaps between tiles) if the geodetic calculations involved (i.e. how to calculate meters from the tile coords) are not done with care.
I am trying to plot a multiline d3 chart. I have created a method which should take a new dataset and try to plot it in the same d3 frame for new data update changes (possibly filters).
The first draw works fine but the next draw (mocked data: which is a slice of the previous data and few manipulated values) is not showing correct is crossing the x axis.
[See Image below]
Also the starting origin is missing a tick which should also be 2010 in this example
I also want to create few more lines if there is more datapoints in the future which should be dynamic. Current model is {date, actual, projected}, More expected is mean or difference which will only be shown on trigger.
Any help would be appreciated.
Here is a Stackblitz https://stackblitz.com/edit/angular-rhr39p
References:
Animated line chart: http://bl.ocks.org/atmccann/8966400
Multiline chart: https://bl.ocks.org/larsenmtl/e3b8b7c2ca4787f77d78f58d41c3da91
Dataset updates: https://bl.ocks.org/d3noob/7030f35b72de721622b8
Please keep just one problem per question here at Stack Overflow. This answer will deal with problem #1, consider asking separate questions for the other problems.
The issue here is just your enter/update methodology, that is not correct and. Stick with the idiomatic D3, which is along these lines:
const update = this.svg.selectAll('.records')
.data(records);
const enter = update.enter().append('g')
.attr('class', 'records');
Then, you append new paths using enter and update those paths using update.
You can also ditch the groups and create enter/update/exit selections for the paths directly. That will make your code simpler.
Here is the forked code: https://stackblitz.com/edit/angular-lyd79t?file=src%2Fapp%2Flinechart%2Flinechart.component.ts
I am working on a project using D3.JS and Flask trying to display a map of the U.S. The problem is that the map is not displaying. I know that that the SVG element is being attached, that the json data is coming through but the map itself is not coming up. I then tried to create a simple index.html document and placed the json file within that project and using a Python simple server was able to see the map. So now for the code.
To start here is the JS code:
<script type="text/javascript">
//Define default path generator
let path = d3.geo.path();
//Creating the SVG element and attaching it to the page.
let svg = d3.select("#us-map")
.append("svg")
.attr("width", 900)
.attr("height", 700);
//This function will get the data for the map of the U.S
d3.json("/json", function(json){
console.log(json.features) //This shows an array of 52 objects
//Bind data and create one path per GeoJSON feature
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path);
});
</script>
Python code:
#app.route("/json")
def json():
data = Data()
data_file = data.convert_json_for_d3()
#return data_file
return data_file.to_json()
The method in the class that I am calling from the above code:
def convert_json_for_d3(self):
self.__data = pd.read_json('us-states.json')
df = self.__data
return df
The HTML:
<section id="us-map">
<h1>UFO Sitings in the U.S.</h1>
</section>
I have been working on this for a day now. At first, getting the json data working with the D3 was the hard part. I figured I had it at that point. However, as I stated, the map is not showing up. It does work if I place it into a simple index.html file along with the json. So I am wondering if the issue is with Flask? One final point, I am following along code from the book Interactive data visualization for the Web. The github repo that I was pulling code from is here: https://github.com/alignedleft/d3-book/blob/master/chapter_12/01_paths.html
Working with a simple HTML file that data appears as this:
object {type: "FeatureCollection", features: Array(52)}
features:Array(52)
0:Object
geometry: Object
coordinates: Array(1)
0: Array (33)
0
1
:
1:Object
:
Data in my Flask Project looks like this:
Object {features: Object, type: Object}
features: Object
0: Object
geometry: Object
coordinates: Array(1)
0: Array (33)
0:Array(2)
1: Object
:
So both the array of objects are almost identical-except for the very first line.
Thank you for any help.
Two issues (based on comments below and updated question)
One is the geojson in your Flask project is not valid. For example features should be an array - not an object, type should still be featureCollection (This is discussed in the comments below). Somewhere along the line your geojson structure is changed to something that isn't accepted by d3.geo.path() as valid geojson.
Two is that you are not using a projection to convert your latitude and longitude pairs (in the geometry of each feature) to svg coordinate space.
For the second issue:
When using d3.geo.path(); you need to specify a projection (eg: d3.geo.path().projection(d3.geo.mercator());). If you do not provide a projection, a null projection is used. This interprets the provided geojson without applying any transformation - essentially your values are translated into pixel values on the svg.
The United States is in the western hemisphere, all the longitudes are therefore negative (and as north south geographic values increase as one goes north and svg y values increase as one moves down, the image will be upside down). A null projection (with no other transform on the svg) will draw a path that is to the left of your svg's boundaries. This is why these three things can happen:
the "SVG element is being attached"
"that the json data is coming through", but
"the map itself is not [visually] coming up"
The geojson referenced in the chapter you reference is unprojected data - it contains a latitude and longitude pair for each vertex: [-133.05341,56.125739]. This is ideal, as a d3.geo.projection takes this type of coordinate, points on a three dimensional ellipsoid, and projects them onto a two dimensional Cartesian plane. If you had already planar data you would need to use a geo transform.
So, to visualize your data you will need to select a projection to convert latitude and longitude pairs into appropriate values. USA albers might be easiest as it is a composite projection that scales down Alaska and moves both Alaska and Hawaii closer to the continental US. The Albers USA also sets all the projection parameters to show the US without modification to projection parameters (center, rotation, parallels, scale etc), while other projections will require setting proper parameters.
I got your data to display with an albersUsa projection using the following code:
var projection = d3.geo.albersUsa().translate([width/2,height/2]);
var path = d3.geo.path().projection(projection);
d3.json("us.json",function(data) {
svg.append("path")
.datum(data)
.attr('d',path)
.attr('fill','steelblue')
.attr('stroke','black');
});
Here is a working demo and a screen shot:
If your map is too large for your svg (or vice versa), you can set the scale with projection.scale(n), with smaller numbers zooming out, larger numbers zooming in.
I have created a webpage displaying markers on an ersi map using javasvipt.
Data:
MapNorth MapEast
439624 504743
439622 504736
439722 504775
439738 504739
439715 504774
439734 504739
The javascript code:
var points = data.map(function(x){
return [x.MapEast, x.MapNorth];
});
var myMultiPoint = {"geometry":{"points":points,"spatialReference":27700},"symbol":{"color":[255,255,255,64],
"size":6,"angle":0,"xoffset":0,"yoffset":0,"type":"esriSMS","style":"esriSMSCircle",
"outline":{"color":[0,0,0,255],"width":6,"type":"esriSLS","style":"esriSLSSolid"}}};
var gra = new esri.Graphic(myMultiPoint);
myMap.graphics.add(gra);
var graExtent = esri.graphicsExtent(myMap.graphics.graphics);
myMap.setExtent(graExtent);
What the above code does is plot markers on the map and then zooms into the extent. What my employers want now is for me to find the central point of all of those points and display one marker in the center.
Can this be done? If so and you tell me how?
Thanks
Paul
Couple of things.
Did you know about gis.stackexchange.com? They might better solve your problem.
What you're trying to do is find the centre of a polygon assuming those points aren't all in a line.
Here's a link with an answer to the question I think you're asking https://gis.stackexchange.com/questions/7998/how-can-i-calculate-the-center-point-inside-a-polygon-in-arcgis-9-3
The solution posted there uses getExtent().getCenter() as seen here
var myPolygonCenterLatLon = myPolygon.getExtent().getCenter();
I think what you want to be doing here is instead of creating a Multipoint, create a Polygon from your array of points. Once you have a polygon defined, you can do something like
var myPolygon = new Polygon(points);
var centroid = myPolygon.getCentroid();
This should get you the centroid of the points making up the Polygon.
https://developers.arcgis.com/javascript/jsapi/polygon-amd.html
Note that this requires at least version 3.7 of the JS API, though.
One thing to point out to those trying to using .getCentriod() , make sure your polygon is closed. Your 1st point and Last Point need to be in the same spot. Otherwise it wont work right. ( I ran into this a year ago, not sure if they changed this)