Ive been trying to create a Mapbox plot like this one: https://docs.mapbox.com/mapbox-gl-js/example/data-driven-circle-colors/) using javascript.
Im trying to create this using data from psql (with feature columns including lat and long) passed through a Python (flask) backend into my html file. I can get the linked plot to work, but can't see how to get my own data in there. Ive tried map.addSource with a GeoJSON file of features but I just can't get it to work. I feel like if I could replicate the data in the link they use I could plot it but I can't see the data!
Any ideas would be great! Im new to JS so the although ive read the documentation I might be missing bits.
Here is the code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Style circles with a data-driven property</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.css" rel="stylesheet" />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
// TO MAKE THE MAP APPEAR YOU MUST
// ADD YOUR ACCESS TOKEN FROM
// https://account.mapbox.com
mapboxgl.accessToken = '<your access token here>';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v10',
zoom: 12,
center: [-122.447303, 37.753574]
});
map.on('load', function() {
/* Sample feature from the `examples.8fgz4egr` tileset:
{
"type": "Feature",
"properties": {
"ethnicity": "White"
},
"geometry": {
"type": "Point",
"coordinates": [ -122.447303, 37.753574 ]
}
}
*/
map.addSource('ethnicity', {
type: 'vector',
url: 'mapbox://examples.8fgz4egr'
});
map.addLayer({
'id': 'population',
'type': 'circle',
'source': 'ethnicity',
'source-layer': 'sf2010',
'paint': {
// make circles larger as the user zooms from z12 to z22
'circle-radius': {
'base': 1.75,
'stops': [
[12, 2],
[22, 180]
]
},
// color circles by ethnicity, using a match expression
// https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-match
'circle-color': [
'match', ['get', 'ethnicity'],
'White',
'#fbb03b',
'Black',
'#223b53',
'Hispanic',
'#e55e5e',
'Asian',
'#3bb2d0',
/* other */
'#ccc'
]
}
});
});
</script>
</body>
</html>
Mapbox GL JS supports GeoJSON source or Vector source to show vector data. i.e there's no other choice to show the data. Here's some options.
Vector tileset
Generating Vector tileset is a bit heavy operation but it is a good choice for client performance
1-1. Host on Mapbox: Managing vector tileset hosted on Mapbox server by using MTS.
1-2. Host on your server: Creating vector tileset on your server by using tippecanoe tool and hosting on your server.
GeoJSON
In general, you will create an endpoint that returns full GeoJSON generated from the database. If the size of GeoJSON is large, it is a nice idea to implement endpoint that takes coordinate and returns nearby data.
In this case, I ended up using geojson in Python to create the json file from the SQLAlchemy data and then passed that from the back end and passed it through to the html file using jinja2.
Then I did:
var data = JSON.parse(‘{{ json_data | tojson }}’)
And then sourced this data into my map!!!
Took a bit of playing around but this seems the smoothest way to get the SQLAlchemy data onto mapbox. Things might get slower when working with more than 200 rows of data But it’s a good solution for now!
Related
Using Open Layers and leaflet-sidebar-v2, I've added the sidebar to my map, this works. However, I also need to add another layer to my map, this layer will outline each country. I have the coordinates stored in a 'borders.json' file. I'm attempting to use D3.json to to import the border coordinates and then L.geoJson to add the new layer to my map.
I'm currently getting the following error message:
Uncaught TypeError: t.getLayerStatesArray is not a function
Here is the relevant part of my code..
var map = new ol.Map({
target: "map",
layers: [
new ol.layer.Tile({
source: new ol.source.OSM(),
}),
],
view: new ol.View({
center: ol.proj.transform([7, 51.2], "EPSG:4326", "EPSG:3857"),
zoom: 3,
}),
});
var sidebar = new ol.control.Sidebar({
element: "sidebar",
position: "left",
});
map.addControl(sidebar);
d3.json(("borders.json"), function (json){
function style(feature) {
return {
fillColor: "transparent",
weight: 1,
opacity: 0.4,
color: 'grey',
fillOpacity: 0.3
}
}
geojson = L.geoJson(json, {
style: style,
}).addTo(map);
})
I think I might be adding the geojson layer to my map incorrectly, but I can't figure out what is wrong. I've spent quite a bit of time playing with it, but no luck.
Any helps is appreciated.
Cheers,
Beat
It might be hard to tell what the problem is without knowing other possible relevant parts of your code. I'd start by checking that the contents of borders.json follows valid GeoJSON format.
This is likely unrelated to your question, but is there a reason that you've declared style as a function like function style(feature) { ... }?
It looks like the style attribute of L.geoJson accepts an object rather than a function.
I want to add clustering to my map from mapbox, I followed the getting started as they suggest:
https://www.mapbox.com/install/js/cdn-add/
And now I have a map, I also added some of my own markers, which are users from my backend that have lats and longs.
So I have a map and some markers.
Now, I want to add clustering, and in the example:
https://docs.mapbox.com/mapbox-gl-js/example/cluster/
they add a source:
map.addSource("earthquakes", {
})
which I don't have, and at this moment I don't think I even need. because I can see the tiles and my markers.
I thought about adding a source, but which source? I don't need a source, I already have what I needed, the tiles and the markers... but the cluster option is in the addSource method on the map. So.. I'm lost here.
This is what they show in the example, but as I said, I don't have or need any other source, as I already see the tiles and my markers, I just want to cluster.
map.addSource("earthquakes", {
type: "geojson",
data: "https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson",
cluster: true,
clusterMaxZoom: 14, // Max zoom to cluster points on
clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50)
});```
I found the solution,
I had to create a geoJson object from my users like this:
const geoJsonMarkers = users.map( (place, i ) => {
const [placeLng, placeLat] = place.location.coordinates;
const position = { lat: placeLat, lng: placeLng };
return {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [position.lng, position.lat]
},
"properties": {
"name": place.name
}
}
})
const usersArray = {
"features": geoJsonMarkers
}
And then pass it to the data property of the source like so:
map.on('load', function() {
// Add a new source from our GeoJSON data and set the
// 'cluster' option to true. GL-JS will add the point_count property to your source data.
map.addSource("users", {
type: "geojson",
// Point to GeoJSON data. This example visualizes all M1.0+ earthquakes
// from 12/22/15 to 1/21/16 as logged by USGS' Earthquake hazards program.
data: usersArray,
cluster: true,
clusterMaxZoom: 14, // Max zoom to cluster points on
clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50)
});
...
the addSource name is arbitrary, could be anything in my case are users so I called it users.
I would like to read/display geoJson data on a Leaflet map. I have 10 multipolygons stored in the geoJson file and would like to color each in a different color.
Reading the documentation on Leaflet's website, I used the following code to read and color the polygons:
//Adding multipolygons to map
L.geoJSON(dataName, {
style: function(feature) {
switch (feature.properties.id) {
case '100': return {color: "#ff0000"};
case '200': return {color: "#0ff000"};
...
case '1000': return {color: "#0000ff"};
}
}
}).addTo(map);
And this is the datafile:
//Data file
var dataName = {"type": "FeatureCollection", "features":[
{ "type":"Feature","id":100,"properties":{"id":"100","count":0},"crs":{"type":"name","properties":{"name":"GEODATA"}},
"geometry":{"type":"MultiPolygon","coordinates":[MANY COORDINATES]
}},
{"type":"Feature","id":200,"properties":{"id":"200","count":0},"crs":{"type":"name","properties":{"name":"GEODATA"}},
"geometry":{"type":"MultiPolygon","coordinates":[MANY COORDINATES]
}},
...
{"type":"Feature","id":1000,"properties":{"id":"1000","count":0},"crs":{"type":"name","properties":{"name":"GEODATA"}},
"geometry":{"type":"MultiPolygon","coordinates":[MANY COORDINATES]
}]}
Nothing is displayed. I think the error lies inside the function. Not really sure what "feature" does. Any clues?
Thx!
It looks like you should be using dataName.features?
L.geoJSON(dataName, {
Should be:
L.geoJSON(dataName.features, {
Here is a code snippet from another answer I made:
geojson = L.geoJson(myGeoJson.features, {
onEachFeature: onEachFeature,
style: styleFeature,
}).addTo(myLeafletMap);
I have being playing around with MapBox and I am having some issues with getting the GeoLocation API to send data back to the map and update the it.
This is what I got right now:
mapboxgl.accessToken = 'TOKEN-HERE';
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mapbox/streets-v9',
center: [-0.968539, 54.562917],
zoom: 9
});
map.on('style.load', function() {
map.addSource("myMap", {
"type": "geojson",
"data": "https://api.mapbox.com/geocoding/v5/mapbox.places/UK_ADDRESS_HERE.json?country=gb&types=address&autocomplete=true&access_token=TOEKN"
});
map.addLayer({
'id': 'test1',
'type': 'line',
'source': 'myMap',
'interactive': true
});
});
The answer may lie with how you are encoding UK_ADDRESS_HERE.
https://api.mapbox.com/geocoding/v5/mapbox.places/UK_ADDRESS_HERE.json
The request format for the Mapbox Geocding API requires that since the {query} parameter can contain any value, it should be URL-encoded.
That means that a simple geocode request like 10 Downing Street, Westminster must be encoded using encodeURIComponent to 10%20Downing%20Street%2C%20Westminster.
Try this and verify that your request is proper.
curl https://api.tiles.mapbox.com/geocoding/v5/mapbox.places/10%20Downing%20Street%2C%20London.json?access_token=${MAPBOX_ACCESS_TOKEN}
I have little Leaflet application where the app get geoJson objects from server, and display it, specially LineString. The JSON parser that i use on server side works properly. And the client side script was ok too.
But some reasons I would like to draw arrow on the routes, and I can't figure out how to do it when using L.geoJson().
Code with L.geoJson():
getJsonFrom(routeQueryURL, params, function(data) {
var a = L.geoJson(data, {
onEachFeature: bindRouteDirection,
}).addTo(map);
});
Because I don't want to change anything on server side, I tried this:
getJsonFrom(routeQueryURL, param, function(data) {
$.each(data, function(index, feature) {
var polyline = new L.Polyline(feature.geometry.coordinates, {
color: feature.properties.color,
opacity: 0.8
}).addTo(routeMapLayer);
var decorator = L.polylineDecorator(polyline, {
patterns: [{
offset: 25,
repeat: 50,
symbol: L.Symbol.arrowHead({
pixelSize: 15,
pathOptions: {
stroke: true,
color: feature.properties.color,
fillOpacity: 0.8,
polygon: false,
weight: 3
}
})
}]
}).addTo(routeMapLayer);
map.addLayer(routeMapLayer);
});
});
So i access the array of coordinates from the geoJson object, and some other data, and draw the polyline directly on to map.The problem is that it's put my route into the middle of middle east instead of Hungary, so it's actually swap the coordinates. Why does L.Polyline handle the different form L.geoJson()?
Use L.GeoJSON.coordsToLatLng() and read why sometimes coordinates are lat-lng and sometimes lng-lat.